第二次提交并推送代码
This commit is contained in:
parent
7e87c8e5b5
commit
6a8c6da49f
@ -0,0 +1,20 @@
|
|||||||
|
package io.dataease;
|
||||||
|
|
||||||
|
import io.dataease.listener.EhCacheStartListener;
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration;
|
||||||
|
import org.springframework.cache.annotation.EnableCaching;
|
||||||
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||||
|
|
||||||
|
@SpringBootApplication(exclude = {QuartzAutoConfiguration.class})
|
||||||
|
@EnableCaching
|
||||||
|
@EnableScheduling
|
||||||
|
public class CoreApplication {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication context = new SpringApplication(CoreApplication.class);
|
||||||
|
context.addInitializers(new EhCacheStartListener());
|
||||||
|
context.run(args);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,70 @@
|
|||||||
|
package io.dataease;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
|
||||||
|
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
|
||||||
|
import com.baomidou.mybatisplus.generator.config.TemplateType;
|
||||||
|
import com.baomidou.mybatisplus.generator.config.converts.MySqlTypeConvert;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 研发使用,请勿提交
|
||||||
|
*/
|
||||||
|
public class MybatisPlusGenerator {
|
||||||
|
/**
|
||||||
|
* 为什么不从配置文件读?
|
||||||
|
* 第一 我嫌麻烦
|
||||||
|
* 第二 后面配置会放到nacos读起来更麻烦了
|
||||||
|
*/
|
||||||
|
private static final String url = "jdbc:mysql://localhost:3306/dataease?autoReconnect=false&useUnicode=true&characterEncoding=UTF-8&characterSetResults=UTF-8&zeroDateTimeBehavior=convertToNull&useSSL=false";
|
||||||
|
private static final String username = "root";
|
||||||
|
private static final String password = "123456";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 业务模块例如datasource,dataset,panel等
|
||||||
|
*/
|
||||||
|
private static final String busi = "visualization";
|
||||||
|
/**
|
||||||
|
* 这是要生成代码的表名称
|
||||||
|
*/
|
||||||
|
private static final String TABLE_NAME = "data_visualization_info";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下面两个配置基本上不用动
|
||||||
|
*/
|
||||||
|
private static final String codeDir = "src/main/java/";
|
||||||
|
|
||||||
|
private static final String AUTO_DAO = ".dao.auto";
|
||||||
|
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception{
|
||||||
|
|
||||||
|
String path = System.getProperty("java.class.path");
|
||||||
|
path = path.substring(0, path.indexOf("target/classes"));
|
||||||
|
String packageName = packageName() + "." + busi + AUTO_DAO;
|
||||||
|
String outPath = path + codeDir;
|
||||||
|
DataSourceConfig.Builder dsc = new DataSourceConfig.Builder(url, username, password);
|
||||||
|
dsc.typeConvert( MySqlTypeConvert.INSTANCE);
|
||||||
|
FastAutoGenerator.create(dsc)
|
||||||
|
.globalConfig(builder -> {
|
||||||
|
builder.author("fit2cloud").outputDir(outPath);
|
||||||
|
})
|
||||||
|
.packageConfig(builder -> {
|
||||||
|
builder.parent(packageName);
|
||||||
|
})
|
||||||
|
.strategyConfig(builder -> {
|
||||||
|
builder.addInclude(TABLE_NAME).entityBuilder().enableFileOverride().mapperBuilder().mapperAnnotation(org.apache.ibatis.annotations.Mapper.class).enableFileOverride(); //设置需要生成的表名
|
||||||
|
})
|
||||||
|
.templateConfig(builder -> {
|
||||||
|
builder.disable(TemplateType.CONTROLLER).disable(TemplateType.SERVICE).disable(TemplateType.SERVICE_IMPL).disable(TemplateType.XML).build();
|
||||||
|
})
|
||||||
|
.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String packageName() {
|
||||||
|
return new Object() {
|
||||||
|
public String getPackageName() {
|
||||||
|
String packageName = this.getClass().getPackageName();
|
||||||
|
return packageName;
|
||||||
|
}
|
||||||
|
}.getPackageName();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
package io.dataease.ai.service;
|
||||||
|
|
||||||
|
import io.dataease.api.ai.AiComponentApi;
|
||||||
|
import io.dataease.commons.utils.UrlTestUtils;
|
||||||
|
import io.dataease.system.manage.SysParameterManage;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author : WangJiaHao
|
||||||
|
* @date : 2024/3/27 09:47
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("aiBase")
|
||||||
|
public class AiBaseService implements AiComponentApi {
|
||||||
|
@Resource
|
||||||
|
private SysParameterManage sysParameterManage;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, String> findTargetUrl() {
|
||||||
|
Map<String, String> templateParams = sysParameterManage.groupVal("ai.");
|
||||||
|
if (templateParams != null && StringUtils.isNotEmpty(templateParams.get("ai.baseUrl"))) {
|
||||||
|
return templateParams;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return new HashMap<>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
package io.dataease.chart.charts;
|
||||||
|
|
||||||
|
import io.dataease.chart.charts.impl.DefaultChartHandler;
|
||||||
|
import io.dataease.extensions.view.plugin.AbstractChartPlugin;
|
||||||
|
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, AbstractChartPlugin> CHART_HANDLER_MAP = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
public void registerChartHandler(String render, String type, AbstractChartPlugin chartHandler) {
|
||||||
|
CHART_HANDLER_MAP.put(render + "-" + type, chartHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AbstractChartPlugin getChartHandler(String render, String type) {
|
||||||
|
var handler = CHART_HANDLER_MAP.get(render + "-" + type);
|
||||||
|
if (handler == null) {
|
||||||
|
return defaultChartHandler;
|
||||||
|
}
|
||||||
|
return handler;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,809 @@
|
|||||||
|
package io.dataease.chart.charts.impl;
|
||||||
|
|
||||||
|
import io.dataease.chart.charts.ChartHandlerManager;
|
||||||
|
import io.dataease.chart.constant.ChartConstants;
|
||||||
|
import io.dataease.chart.manage.ChartDataManage;
|
||||||
|
import io.dataease.chart.manage.ChartViewManege;
|
||||||
|
import io.dataease.chart.utils.ChartDataBuild;
|
||||||
|
import io.dataease.dataset.manage.DatasetTableFieldManage;
|
||||||
|
import io.dataease.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.exception.DEException;
|
||||||
|
import io.dataease.extensions.datasource.api.PluginManageApi;
|
||||||
|
import io.dataease.extensions.datasource.dto.DatasetTableFieldDTO;
|
||||||
|
import io.dataease.extensions.datasource.dto.DatasourceRequest;
|
||||||
|
import io.dataease.extensions.datasource.dto.DatasourceSchemaDTO;
|
||||||
|
import io.dataease.extensions.datasource.model.SQLMeta;
|
||||||
|
import io.dataease.extensions.datasource.provider.Provider;
|
||||||
|
import io.dataease.extensions.datasource.vo.DatasourceConfiguration;
|
||||||
|
import io.dataease.extensions.datasource.vo.XpackPluginsDatasourceVO;
|
||||||
|
import io.dataease.extensions.view.dto.*;
|
||||||
|
import io.dataease.extensions.view.plugin.AbstractChartPlugin;
|
||||||
|
import io.dataease.extensions.view.util.ChartDataUtil;
|
||||||
|
import io.dataease.extensions.view.util.FieldUtil;
|
||||||
|
import io.dataease.license.utils.LicenseUtil;
|
||||||
|
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.collections4.CollectionUtils;
|
||||||
|
import org.apache.commons.collections4.MapUtils;
|
||||||
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.math.RoundingMode;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class DefaultChartHandler extends AbstractChartPlugin {
|
||||||
|
public static Logger logger = LoggerFactory.getLogger(ChartDataManage.class);
|
||||||
|
@Resource
|
||||||
|
protected ChartHandlerManager chartHandlerManager;
|
||||||
|
@Resource
|
||||||
|
protected DatasetTableFieldManage datasetTableFieldManage;
|
||||||
|
@Resource
|
||||||
|
protected ChartViewManege chartViewManege;
|
||||||
|
@Getter
|
||||||
|
private String render = "antv";
|
||||||
|
@Getter
|
||||||
|
private String type = "*";
|
||||||
|
@Autowired(required = false)
|
||||||
|
public PluginManageApi pluginManage;
|
||||||
|
|
||||||
|
@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> T customFilter(ChartViewDTO view, List<ChartExtFilterDTO> filterList, AxisFormatResult formatResult) {
|
||||||
|
var desensitizationList = (Map<String, ColumnPermissionItem>) formatResult.getContext().get("desensitizationList");
|
||||||
|
if (MapUtils.isNotEmpty(desensitizationList)) {
|
||||||
|
formatResult.getAxisMap().forEach((axis, fields) -> {
|
||||||
|
fields.removeIf(f -> desensitizationList.containsKey(f.getDataeaseName()));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
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, Provider 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 = (List<ChartViewFieldDTO>) filterResult.getContext().get("allFields");
|
||||||
|
Dimension2SQLObj.dimension2sqlObj(sqlMeta, xAxis, FieldUtil.transFields(allFields), crossDs, dsMap, Utils.getParams(FieldUtil.transFields(allFields)), view.getCalParams(), pluginManage);
|
||||||
|
Quota2SQLObj.quota2sqlObj(sqlMeta, yAxis, FieldUtil.transFields(allFields), crossDs, dsMap, Utils.getParams(FieldUtil.transFields(allFields)), view.getCalParams(), pluginManage);
|
||||||
|
String querySql = SQLProvider.createQuerySQL(sqlMeta, true, needOrder, view);
|
||||||
|
querySql = provider.rebuildSQL(querySql, sqlMeta, crossDs, dsMap);
|
||||||
|
datasourceRequest.setQuery(querySql);
|
||||||
|
logger.debug("calcite chart sql: " + querySql);
|
||||||
|
List<String[]> data = (List<String[]>) provider.fetchResultField(datasourceRequest).get("data");
|
||||||
|
//自定义排序
|
||||||
|
data = ChartDataUtil.resultCustomSort(xAxis, yAxis, view.getSortPriority(), data);
|
||||||
|
//快速计算
|
||||||
|
var extStack = formatResult.getAxisMap().get(ChartAxis.extStack);
|
||||||
|
var xAxisExt = formatResult.getAxisMap().get(ChartAxis.xAxisExt);
|
||||||
|
quickCalc(xAxis, yAxis, xAxisExt, extStack, view.getType(), 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChartViewDTO buildChart(ChartViewDTO view, ChartCalcDataResult calcResult, AxisFormatResult formatResult, CustomFilterResult filterResult) {
|
||||||
|
var desensitizationList = (Map<String, ColumnPermissionItem>) filterResult.getContext().get("desensitizationList");
|
||||||
|
var allFields = (List<ChartViewFieldDTO>) filterResult.getContext().get("allFields");
|
||||||
|
var xAxis = formatResult.getAxisMap().get(ChartAxis.xAxis);
|
||||||
|
var yAxis = formatResult.getAxisMap().get(ChartAxis.yAxis);
|
||||||
|
// 如果是表格导出查询 则在此处直接就可以返回
|
||||||
|
var extStack = formatResult.getAxisMap().get(ChartAxis.extStack);
|
||||||
|
if (CollectionUtils.isNotEmpty(extStack) && xAxis.size() > extStack.size()) {
|
||||||
|
xAxis = xAxis.subList(0, xAxis.size() - extStack.size());
|
||||||
|
}
|
||||||
|
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> mapTableNormal = ChartDataBuild.transTableNormal(xAxis, yAxis, view, calcResult.getOriginData(), extStack, desensitizationList);
|
||||||
|
var drillFilters = filterResult.getFilterList().stream().filter(f -> f.getFilterType() == 1).collect(Collectors.toList());
|
||||||
|
// 日期下钻替换回去
|
||||||
|
drillFilters.forEach(f -> {
|
||||||
|
if (CollectionUtils.isNotEmpty(f.getOriginValue())) {
|
||||||
|
f.setValue(f.getOriginValue());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var isDrill = CollectionUtils.isNotEmpty(drillFilters);
|
||||||
|
// 构建结果
|
||||||
|
Map<String, Object> dataMap = new HashMap<>();
|
||||||
|
dataMap.putAll(calcResult.getData());
|
||||||
|
dataMap.putAll(mapTableNormal);
|
||||||
|
dataMap.put("sourceFields", allFields);
|
||||||
|
mergeAssistField(calcResult.getDynamicAssistFields(), calcResult.getAssistData());
|
||||||
|
dataMap.put("dynamicAssistLines", calcResult.getDynamicAssistFields());
|
||||||
|
view.setData(dataMap);
|
||||||
|
view.setSql(Base64.getEncoder().encodeToString(calcResult.getQuerySql().getBytes()));
|
||||||
|
view.setDrill(isDrill);
|
||||||
|
view.setDrillFilters(drillFilters);
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected void mergeAssistField(List<ChartSeniorAssistDTO> dynamicAssistFields, List<String[]> assistData) {
|
||||||
|
if (ObjectUtils.isEmpty(assistData)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String[] strings = assistData.get(0);
|
||||||
|
for (int i = 0; i < dynamicAssistFields.size(); i++) {
|
||||||
|
if (i < strings.length) {
|
||||||
|
ChartSeniorAssistDTO chartSeniorAssistDTO = dynamicAssistFields.get(i);
|
||||||
|
chartSeniorAssistDTO.setValue(strings[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected List<ChartSeniorAssistDTO> getDynamicAssistFields(ChartViewDTO view) {
|
||||||
|
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 List<ChartViewFieldDTO> getAssistFields(List<ChartSeniorAssistDTO> list, List<ChartViewFieldDTO> yAxis, List<ChartViewFieldDTO> xAxis) {
|
||||||
|
List<ChartViewFieldDTO> res = new ArrayList<>();
|
||||||
|
for (ChartSeniorAssistDTO dto : list) {
|
||||||
|
DatasetTableFieldDTO curField = dto.getCurField();
|
||||||
|
ChartViewFieldDTO field = null;
|
||||||
|
String alias = "";
|
||||||
|
for (int i = 0; i < yAxis.size(); i++) {
|
||||||
|
ChartViewFieldDTO yField = yAxis.get(i);
|
||||||
|
if (Objects.equals(yField.getId(), curField.getId())) {
|
||||||
|
field = yField;
|
||||||
|
alias = String.format(SQLConstants.FIELD_ALIAS_Y_PREFIX, i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ObjectUtils.isEmpty(field) && CollectionUtils.isNotEmpty(xAxis)) {
|
||||||
|
for (int i = 0; i < xAxis.size(); i++) {
|
||||||
|
ChartViewFieldDTO xField = xAxis.get(i);
|
||||||
|
if (StringUtils.equalsIgnoreCase(String.valueOf(xField.getId()), String.valueOf(curField.getId()))) {
|
||||||
|
field = xField;
|
||||||
|
alias = String.format(SQLConstants.FIELD_ALIAS_X_PREFIX, i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ObjectUtils.isEmpty(field)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ChartViewFieldDTO chartViewFieldDTO = new ChartViewFieldDTO();
|
||||||
|
BeanUtils.copyBean(chartViewFieldDTO, curField);
|
||||||
|
chartViewFieldDTO.setSummary(dto.getSummary());
|
||||||
|
chartViewFieldDTO.setOriginName(alias);// yAxis的字段别名,就是查找的字段名
|
||||||
|
res.add(chartViewFieldDTO);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ChartSeniorAssistDTO> getDynamicThresholdFields(ChartViewDTO view) {
|
||||||
|
List<ChartSeniorAssistDTO> list = new ArrayList<>();
|
||||||
|
Map<String, Object> senior = view.getSenior();
|
||||||
|
if (ObjectUtils.isEmpty(senior)) {
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
ChartSeniorThresholdCfgDTO thresholdCfg = JsonUtil.parseObject((String) JsonUtil.toJSONString(senior.get("threshold")), ChartSeniorThresholdCfgDTO.class);
|
||||||
|
|
||||||
|
if (null == thresholdCfg || !thresholdCfg.isEnable()) {
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
List<TableThresholdDTO> tableThreshold = thresholdCfg.getTableThreshold();
|
||||||
|
|
||||||
|
if (ObjectUtils.isEmpty(tableThreshold)) {
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<ChartSeniorThresholdDTO> conditionsList = tableThreshold.stream()
|
||||||
|
.filter(item -> !ObjectUtils.isEmpty(item))
|
||||||
|
.map(TableThresholdDTO::getConditions)
|
||||||
|
.flatMap(List::stream)
|
||||||
|
.filter(condition -> StringUtils.equalsAnyIgnoreCase(condition.getType(), "dynamic"))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
List<ChartSeniorAssistDTO> assistDTOs = conditionsList.stream()
|
||||||
|
.flatMap(condition -> getConditionFields(condition).stream())
|
||||||
|
.filter(this::solveThresholdCondition)
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
list.addAll(assistDTOs);
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean solveThresholdCondition(ChartSeniorAssistDTO fieldDTO) {
|
||||||
|
Long fieldId = fieldDTO.getFieldId();
|
||||||
|
String summary = fieldDTO.getValue();
|
||||||
|
if (ObjectUtils.isEmpty(fieldId) || StringUtils.isEmpty(summary)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
DatasetTableFieldDTO datasetTableFieldDTO = datasetTableFieldManage.selectById(fieldId);
|
||||||
|
if (ObjectUtils.isEmpty(datasetTableFieldDTO)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ChartViewFieldDTO datasetTableField = new ChartViewFieldDTO();
|
||||||
|
BeanUtils.copyBean(datasetTableField, datasetTableFieldDTO);
|
||||||
|
fieldDTO.setCurField(datasetTableField);
|
||||||
|
fieldDTO.setSummary(summary);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<ChartSeniorAssistDTO> getConditionFields(ChartSeniorThresholdDTO condition) {
|
||||||
|
List<ChartSeniorAssistDTO> list = new ArrayList<>();
|
||||||
|
if ("between".equals(condition.getTerm())) {
|
||||||
|
if (!StringUtils.equalsIgnoreCase(condition.getDynamicMaxField().getSummary(), "value")) {
|
||||||
|
list.add(of(condition.getDynamicMaxField()));
|
||||||
|
}
|
||||||
|
if (!StringUtils.equalsIgnoreCase(condition.getDynamicMinField().getSummary(), "value")) {
|
||||||
|
list.add(of(condition.getDynamicMinField()));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!StringUtils.equalsIgnoreCase(condition.getDynamicField().getSummary(), "value")) {
|
||||||
|
list.add(of(condition.getDynamicField()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ChartSeniorAssistDTO of(ThresholdDynamicFieldDTO dynamicField) {
|
||||||
|
ChartSeniorAssistDTO conditionField = new ChartSeniorAssistDTO();
|
||||||
|
conditionField.setFieldId(Long.parseLong(dynamicField.getFieldId()));
|
||||||
|
conditionField.setValue(dynamicField.getSummary());
|
||||||
|
return conditionField;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String assistSQL(String sql, List<ChartViewFieldDTO> assistFields, Map<Long, DatasourceSchemaDTO> dsMap) {
|
||||||
|
// get datasource prefix and suffix
|
||||||
|
String dsType = dsMap.entrySet().iterator().next().getValue().getType();
|
||||||
|
String prefix = "";
|
||||||
|
String suffix = "";
|
||||||
|
if (Arrays.stream(DatasourceConfiguration.DatasourceType.values()).map(DatasourceConfiguration.DatasourceType::getType).toList().contains(dsType)) {
|
||||||
|
DatasourceConfiguration.DatasourceType datasourceType = DatasourceConfiguration.DatasourceType.valueOf(dsType);
|
||||||
|
prefix = datasourceType.getPrefix();
|
||||||
|
suffix = datasourceType.getSuffix();
|
||||||
|
} else {
|
||||||
|
if (LicenseUtil.licenseValid()) {
|
||||||
|
List<XpackPluginsDatasourceVO> xpackPluginsDatasourceVOS = pluginManage.queryPluginDs();
|
||||||
|
List<XpackPluginsDatasourceVO> list = xpackPluginsDatasourceVOS.stream().filter(ele -> StringUtils.equals(ele.getType(), dsType)).toList();
|
||||||
|
if (ObjectUtils.isNotEmpty(list)) {
|
||||||
|
XpackPluginsDatasourceVO first = list.getFirst();
|
||||||
|
prefix = first.getPrefix();
|
||||||
|
suffix = first.getSuffix();
|
||||||
|
} else {
|
||||||
|
DEException.throwException("当前数据源插件不存在");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean crossDs = Utils.isCrossDs(dsMap);
|
||||||
|
StringBuilder stringBuilder = new StringBuilder();
|
||||||
|
for (int i = 0; i < assistFields.size(); i++) {
|
||||||
|
ChartViewFieldDTO dto = assistFields.get(i);
|
||||||
|
if (crossDs) {
|
||||||
|
if (i == (assistFields.size() - 1)) {
|
||||||
|
stringBuilder.append(dto.getSummary() + "(" + dto.getOriginName() + ")");
|
||||||
|
} else {
|
||||||
|
stringBuilder.append(dto.getSummary() + "(" + dto.getOriginName() + "),");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (i == (assistFields.size() - 1)) {
|
||||||
|
stringBuilder.append(dto.getSummary() + "(" + prefix + dto.getOriginName() + suffix + ")");
|
||||||
|
} else {
|
||||||
|
stringBuilder.append(dto.getSummary() + "(" + prefix + dto.getOriginName() + suffix + "),");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "SELECT " + stringBuilder + " FROM (" + sql + ") tmp";
|
||||||
|
}
|
||||||
|
|
||||||
|
protected List<String> mergeIds(List<ChartViewFieldDTO> xAxisExt, List<ChartViewFieldDTO> extStack) {
|
||||||
|
Set<String> idSet = new HashSet<>();
|
||||||
|
if (xAxisExt != null) {
|
||||||
|
xAxisExt.forEach(field -> idSet.add(String.valueOf(field.getId())));
|
||||||
|
}
|
||||||
|
if (extStack != null) {
|
||||||
|
extStack.forEach(field -> idSet.add(String.valueOf(field.getId())));
|
||||||
|
}
|
||||||
|
return new ArrayList<>(idSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void quickCalc(List<ChartViewFieldDTO> xAxis, List<ChartViewFieldDTO> yAxis
|
||||||
|
, List<ChartViewFieldDTO> xAxisExt, List<ChartViewFieldDTO> extStack, String chartType, 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(resultData, "pre")) {
|
||||||
|
item[dataIndex] = new BigDecimal(lastValue).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();
|
||||||
|
}
|
||||||
|
} else if (StringUtils.equalsIgnoreCase(compareCalc.getType(), "accumulate")) {
|
||||||
|
// 累加
|
||||||
|
if (CollectionUtils.isEmpty(data)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (StringUtils.containsAny(chartType, "group", "stack")) {
|
||||||
|
if (CollectionUtils.isEmpty(xAxis)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (StringUtils.containsIgnoreCase(chartType, "stack") && extStack.isEmpty()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (StringUtils.containsIgnoreCase(chartType, "group") && xAxisExt.isEmpty()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
final Map<String, Integer> mainIndexMap = new HashMap<>();
|
||||||
|
final List<List<String[]>> mainMatrix = new ArrayList<>();
|
||||||
|
// 排除group和stack的字段
|
||||||
|
List<String> groupStackAxisIds = mergeIds(xAxisExt, extStack);
|
||||||
|
List<ChartViewFieldDTO> finalXAxisBase = xAxis.stream().filter(ele->!groupStackAxisIds.contains(String.valueOf(ele.getId()))).toList();
|
||||||
|
if (CollectionUtils.isEmpty(finalXAxisBase) && CollectionUtils.isNotEmpty(xAxis)) {
|
||||||
|
finalXAxisBase.add(xAxis.get(0));
|
||||||
|
}
|
||||||
|
data.forEach(item -> {
|
||||||
|
String[] mainAxisArr = Arrays.copyOfRange(item, 0, finalXAxisBase.size());
|
||||||
|
String mainAxis = StringUtils.join(mainAxisArr, '-');
|
||||||
|
Integer index = mainIndexMap.get(mainAxis);
|
||||||
|
if (index == null) {
|
||||||
|
mainIndexMap.put(mainAxis, mainMatrix.size());
|
||||||
|
List<String[]> tmp = new ArrayList<>();
|
||||||
|
tmp.add(item);
|
||||||
|
mainMatrix.add(tmp);
|
||||||
|
} else {
|
||||||
|
List<String[]> tmp = mainMatrix.get(index);
|
||||||
|
tmp.add(item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
int finalDataIndex = dataIndex;
|
||||||
|
int subEndIndex = finalXAxisBase.size();
|
||||||
|
if (StringUtils.containsIgnoreCase(chartType, "group")) {
|
||||||
|
subEndIndex += xAxisExt.size();
|
||||||
|
}
|
||||||
|
if (StringUtils.containsIgnoreCase(chartType, "stack")) {
|
||||||
|
subEndIndex += extStack.size();
|
||||||
|
}
|
||||||
|
int finalSubEndIndex = subEndIndex;
|
||||||
|
//滑动累加
|
||||||
|
for (int k = 1; k < mainMatrix.size(); k++) {
|
||||||
|
List<String[]> preDataItems = mainMatrix.get(k - 1);
|
||||||
|
List<String[]> curDataItems = mainMatrix.get(k);
|
||||||
|
Map<String, BigDecimal> preDataMap = new HashMap<>();
|
||||||
|
preDataItems.forEach(preDataItem -> {
|
||||||
|
String[] groupStackAxisArr = Arrays.copyOfRange(preDataItem, finalXAxisBase.size(), finalSubEndIndex);
|
||||||
|
String groupStackAxis = StringUtils.join(groupStackAxisArr, '-');
|
||||||
|
String preVal = preDataItem[finalDataIndex];
|
||||||
|
if (StringUtils.isBlank(preVal)) {
|
||||||
|
preVal = "0";
|
||||||
|
}
|
||||||
|
preDataMap.put(groupStackAxis, new BigDecimal(preVal));
|
||||||
|
});
|
||||||
|
curDataItems.forEach(curDataItem -> {
|
||||||
|
String[] groupStackAxisArr = Arrays.copyOfRange(curDataItem, finalXAxisBase.size(), finalSubEndIndex);
|
||||||
|
String groupStackAxis = StringUtils.join(groupStackAxisArr, '-');
|
||||||
|
BigDecimal preValue = preDataMap.get(groupStackAxis);
|
||||||
|
if (preValue != null) {
|
||||||
|
curDataItem[finalDataIndex] = new BigDecimal(curDataItem[finalDataIndex])
|
||||||
|
.add(preValue)
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
final int index = dataIndex;
|
||||||
|
final AtomicReference<BigDecimal> accumValue = new AtomicReference<>(new BigDecimal(0));
|
||||||
|
data.forEach(item -> {
|
||||||
|
String val = item[index];
|
||||||
|
BigDecimal curAccumValue = accumValue.get();
|
||||||
|
if (!StringUtils.isBlank(val)) {
|
||||||
|
BigDecimal curVal = new BigDecimal(val);
|
||||||
|
curAccumValue = curAccumValue.add(curVal);
|
||||||
|
accumValue.set(curAccumValue);
|
||||||
|
}
|
||||||
|
item[index] = curAccumValue.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 || filterDTO.getFilterType() == 2)) {
|
||||||
|
// -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.getFirst();
|
||||||
|
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.setOriginValue(Collections.singletonList(dimValMap.get(tmpField.getId())));
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -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 YoyChartHandler {
|
||||||
|
@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;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,184 @@
|
|||||||
|
package io.dataease.chart.charts.impl;
|
||||||
|
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
|
import io.dataease.engine.sql.SQLProvider;
|
||||||
|
import io.dataease.engine.trans.ExtWhere2Str;
|
||||||
|
import io.dataease.engine.utils.Utils;
|
||||||
|
import io.dataease.extensions.datasource.dto.DatasourceRequest;
|
||||||
|
import io.dataease.extensions.datasource.dto.DatasourceSchemaDTO;
|
||||||
|
import io.dataease.extensions.datasource.model.SQLMeta;
|
||||||
|
import io.dataease.extensions.datasource.provider.Provider;
|
||||||
|
import io.dataease.extensions.view.dto.*;
|
||||||
|
import io.dataease.extensions.view.util.FieldUtil;
|
||||||
|
import io.dataease.utils.JsonUtil;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 带同环比计算的图表处理器
|
||||||
|
*/
|
||||||
|
public class YoyChartHandler extends DefaultChartHandler {
|
||||||
|
@Override
|
||||||
|
public <T extends CustomFilterResult> T customFilter(ChartViewDTO view, List<ChartExtFilterDTO> filterList, AxisFormatResult formatResult) {
|
||||||
|
var result = super.customFilter(view, filterList, 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) result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@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, Provider 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, Utils.getParams(FieldUtil.transFields(allFields)), view.getCalParams(), pluginManage);
|
||||||
|
var originSql = SQLProvider.createQuerySQL(sqlMeta, true, needOrder, view);
|
||||||
|
originSql = provider.rebuildSQL(originSql, sqlMeta, crossDs, dsMap);
|
||||||
|
var request = new DatasourceRequest();
|
||||||
|
request.setDsList(dsMap);
|
||||||
|
request.setQuery(originSql);
|
||||||
|
logger.debug("calcite yoy sql: " + 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(resultData);
|
||||||
|
expandedResult.setQuerySql(originSql);
|
||||||
|
}
|
||||||
|
// 同环比数据排序
|
||||||
|
expandedResult.setOriginData(sortData(view, expandedResult.getOriginData(), formatResult));
|
||||||
|
return expandedResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<String[]> sortData(ChartViewDTO view, List<String[]> data, AxisFormatResult formatResult) {
|
||||||
|
// 维度排序
|
||||||
|
List<ChartViewFieldDTO> xAxisSortList = view.getXAxis().stream().filter(x -> !StringUtils.equalsIgnoreCase("none", x.getSort())).toList();
|
||||||
|
// 指标排序
|
||||||
|
List<ChartViewFieldDTO> yAxisSortList = view.getYAxis().stream().filter(y -> {
|
||||||
|
//需要针对区间条形图的时间类型判断一下
|
||||||
|
if (StringUtils.equalsIgnoreCase("bar-range", view.getType()) && StringUtils.equalsIgnoreCase(y.getGroupType(), "d") && y.getDeType() == 1) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return !StringUtils.equalsIgnoreCase("none", y.getSort());
|
||||||
|
}
|
||||||
|
}).toList();
|
||||||
|
// 不包含维度排序时,指标排序生效
|
||||||
|
if (!data.isEmpty() && CollectionUtils.isEmpty(xAxisSortList) && CollectionUtils.isNotEmpty(yAxisSortList)) {
|
||||||
|
// 指标排序仅第一个生效
|
||||||
|
ChartViewFieldDTO firstYAxis = yAxisSortList.getFirst();
|
||||||
|
boolean asc = firstYAxis.getSort().equalsIgnoreCase("asc");
|
||||||
|
// 维度指标
|
||||||
|
List<ChartViewFieldDTO> allAxisList = new ArrayList<>();
|
||||||
|
allAxisList.addAll(formatResult.getAxisMap().get(ChartAxis.xAxis));
|
||||||
|
allAxisList.addAll(formatResult.getAxisMap().get(ChartAxis.yAxis));
|
||||||
|
int index = findIndex(allAxisList, firstYAxis.getId());
|
||||||
|
return sortData(data, asc, index);
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<String[]> sortData(List<String[]> data, boolean ascending, int index) {
|
||||||
|
Comparator<String[]> comparator;
|
||||||
|
if (ascending) {
|
||||||
|
comparator = Comparator.comparing(item -> toBigDecimal(item[index]), Comparator.nullsFirst(Comparator.naturalOrder()));
|
||||||
|
} else {
|
||||||
|
comparator = Comparator.comparing(item -> toBigDecimal(item[index]), Comparator.nullsLast(Comparator.reverseOrder()));
|
||||||
|
}
|
||||||
|
return data.stream().sorted(comparator).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BigDecimal toBigDecimal(String value) {
|
||||||
|
if (value == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return new BigDecimal(value);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
throw new IllegalArgumentException("Invalid number format: " + value, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int findIndex(List<ChartViewFieldDTO> list, Long id) {
|
||||||
|
for (int i = 0; i < list.size(); i++) {
|
||||||
|
if (StringUtils.equalsIgnoreCase(list.get(i).getId().toString(), id.toString())) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,68 @@
|
|||||||
|
package io.dataease.chart.charts.impl.bar;
|
||||||
|
|
||||||
|
import io.dataease.chart.charts.impl.YoyChartHandler;
|
||||||
|
import io.dataease.engine.utils.Utils;
|
||||||
|
import io.dataease.extensions.datasource.dto.DatasourceRequest;
|
||||||
|
import io.dataease.extensions.datasource.dto.DatasourceSchemaDTO;
|
||||||
|
import io.dataease.extensions.datasource.model.SQLMeta;
|
||||||
|
import io.dataease.extensions.datasource.provider.Provider;
|
||||||
|
import io.dataease.extensions.view.dto.*;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@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, Provider 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, dsMap);
|
||||||
|
req.setQuery(assistSql);
|
||||||
|
logger.debug("calcite assistSql sql: " + assistSql);
|
||||||
|
var assistData = (List<String[]>) provider.fetchResultField(req).get("data");
|
||||||
|
result.setAssistData(assistData);
|
||||||
|
result.setDynamicAssistFields(dynamicAssistFields);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
@ -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";
|
||||||
|
}
|
@ -0,0 +1,73 @@
|
|||||||
|
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.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@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> T customFilter(ChartViewDTO view, List<ChartExtFilterDTO> filterList, AxisFormatResult 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 drillAxis = xAxis.stream().filter(axis -> FieldSource.DRILL == axis.getSource()).toList();
|
||||||
|
var xAxisBase = xAxis.subList(0, xAxis.size() - xAxisExt.size() - drillAxis.size());
|
||||||
|
return ChartDataBuild.transBaseGroupDataAntV(xAxisBase, xAxis, xAxisExt, yAxis, view, data, isDrill);
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,83 @@
|
|||||||
|
package io.dataease.chart.charts.impl.bar;
|
||||||
|
|
||||||
|
import io.dataease.chart.charts.impl.YoyChartHandler;
|
||||||
|
import io.dataease.chart.utils.ChartDataBuild;
|
||||||
|
import io.dataease.extensions.datasource.model.SQLMeta;
|
||||||
|
import io.dataease.extensions.datasource.provider.Provider;
|
||||||
|
import io.dataease.extensions.view.dto.*;
|
||||||
|
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 final 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());
|
||||||
|
var xAxisBase = 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);
|
||||||
|
result.getContext().put("xAxisBase", xAxisBase);
|
||||||
|
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 xAxisBase = (List<ChartViewFieldDTO>) formatResult.getContext().get("xAxisBase");
|
||||||
|
var skipBarRange = (boolean) formatResult.getContext().get("skipBarRange");
|
||||||
|
var barRangeDate = (boolean) formatResult.getContext().get("barRangeDate");
|
||||||
|
Map<String, Object> result = ChartDataBuild.transBarRangeDataAntV(skipBarRange, barRangeDate, xAxisBase, 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, Provider provider) {
|
||||||
|
sqlMeta.setChartType(this.type);
|
||||||
|
return super.calcChartResult(view, formatResult, filterResult, sqlMap, sqlMeta, provider);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,72 @@
|
|||||||
|
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> T customFilter(ChartViewDTO view, List<ChartExtFilterDTO> filterList, AxisFormatResult 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 drillAxis = xAxis.stream().filter(axis -> FieldSource.DRILL == axis.getSource()).toList();
|
||||||
|
var xAxisBase = xAxis.subList(0, xAxis.size() - extStack.size() - drillAxis.size());
|
||||||
|
return ChartDataBuild.transStackChartDataAntV(xAxisBase, xAxis, yAxis, view, data, extStack, isDrill);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,88 @@
|
|||||||
|
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.extStack, view.getExtStack());
|
||||||
|
result.getAxisMap().put(ChartAxis.xAxisExt, view.getXAxisExt());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends CustomFilterResult> T customFilter(ChartViewDTO view, List<ChartExtFilterDTO> filterList, AxisFormatResult 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());
|
||||||
|
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 drillAxis = xAxis.stream().filter(axis -> FieldSource.DRILL == axis.getSource()).toList();
|
||||||
|
var xAxisBase = xAxis.subList(0, xAxis.size() - xAxisExt.size() - extStack.size() - drillAxis.size());
|
||||||
|
return ChartDataBuild.transGroupStackDataAntV(xAxisBase, xAxis, xAxisExt, yAxis, extStack, data, view, isDrill);
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,80 @@
|
|||||||
|
package io.dataease.chart.charts.impl.line;
|
||||||
|
|
||||||
|
import io.dataease.chart.charts.impl.YoyChartHandler;
|
||||||
|
import io.dataease.chart.utils.ChartDataBuild;
|
||||||
|
import io.dataease.extensions.datasource.dto.DatasourceRequest;
|
||||||
|
import io.dataease.extensions.datasource.dto.DatasourceSchemaDTO;
|
||||||
|
import io.dataease.extensions.datasource.model.SQLMeta;
|
||||||
|
import io.dataease.extensions.datasource.provider.Provider;
|
||||||
|
import io.dataease.extensions.view.dto.*;
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
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 drillAxis = xAxis.stream().filter(axis -> FieldSource.DRILL == axis.getSource()).toList();
|
||||||
|
var xAxisBase = xAxis.subList(0, xAxis.size() - xAxisExt.size() - drillAxis.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, Provider 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());
|
||||||
|
}
|
||||||
|
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, dsMap);
|
||||||
|
req.setQuery(assistSql);
|
||||||
|
logger.debug("calcite assistSql sql: " + assistSql);
|
||||||
|
var assistData = (List<String[]>) provider.fetchResultField(req).get("data");
|
||||||
|
result.setAssistData(assistData);
|
||||||
|
result.setDynamicAssistFields(dynamicAssistFields);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,115 @@
|
|||||||
|
package io.dataease.chart.charts.impl.line;
|
||||||
|
|
||||||
|
import io.dataease.chart.charts.impl.YoyChartHandler;
|
||||||
|
import io.dataease.chart.utils.ChartDataBuild;
|
||||||
|
import io.dataease.engine.utils.Utils;
|
||||||
|
import io.dataease.extensions.datasource.dto.DatasourceRequest;
|
||||||
|
import io.dataease.extensions.datasource.dto.DatasourceSchemaDTO;
|
||||||
|
import io.dataease.extensions.datasource.model.SQLMeta;
|
||||||
|
import io.dataease.extensions.datasource.provider.Provider;
|
||||||
|
import io.dataease.extensions.view.dto.*;
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
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 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 yAxis = formatResult.getAxisMap().get(ChartAxis.yAxis);
|
||||||
|
var drillAxis = xAxis.stream().filter(axis -> FieldSource.DRILL == axis.getSource()).toList();
|
||||||
|
var xAxisBase = xAxis.subList(0, xAxis.size() - extStack.size() - drillAxis.size());
|
||||||
|
return ChartDataBuild.transStackChartDataAntV(xAxisBase, xAxis, yAxis, view, data, extStack, isDrill);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends CustomFilterResult> T customFilter(ChartViewDTO view, List<ChartExtFilterDTO> filterList, AxisFormatResult 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, Provider 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, dsMap);
|
||||||
|
req.setQuery(assistSql);
|
||||||
|
logger.debug("calcite assist sql: " + assistSql);
|
||||||
|
var assistData = (List<String[]>) provider.fetchResultField(req).get("data");
|
||||||
|
result.setAssistData(assistData);
|
||||||
|
result.setDynamicAssistFields(dynamicAssistFields);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
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.ChartViewDTO;
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class BubbleMapHandler extends ExtQuotaChartHandler {
|
||||||
|
@Getter
|
||||||
|
private String type = "bubble-map";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AxisFormatResult formatAxis(ChartViewDTO view) {
|
||||||
|
return super.formatAxis(view);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,26 @@
|
|||||||
|
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;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class FlowMapHandler extends GroupChartHandler {
|
||||||
|
@Getter
|
||||||
|
private String type = "flow-map";
|
||||||
|
@Override
|
||||||
|
public AxisFormatResult formatAxis(ChartViewDTO view) {
|
||||||
|
var result = super.formatAxis(view);
|
||||||
|
var xAxis = result.getAxisMap().get(ChartAxis.xAxis);
|
||||||
|
xAxis.addAll(Optional.ofNullable(view.getFlowMapStartName()).orElse(new ArrayList<>()));
|
||||||
|
xAxis.addAll(Optional.ofNullable(view.getFlowMapEndName()).orElse(new ArrayList<>()));
|
||||||
|
result.getAxisMap().put(ChartAxis.xAxis, xAxis);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -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";
|
||||||
|
}
|
@ -0,0 +1,153 @@
|
|||||||
|
package io.dataease.chart.charts.impl.map;
|
||||||
|
|
||||||
|
import io.dataease.chart.charts.impl.GroupChartHandler;
|
||||||
|
import io.dataease.chart.utils.ChartDataBuild;
|
||||||
|
import io.dataease.dataset.manage.DatasetDataManage;
|
||||||
|
import io.dataease.engine.sql.SQLProvider;
|
||||||
|
import io.dataease.engine.trans.Dimension2SQLObj;
|
||||||
|
import io.dataease.engine.trans.Field2SQLObj;
|
||||||
|
import io.dataease.engine.trans.Quota2SQLObj;
|
||||||
|
import io.dataease.engine.trans.Table2SQLObj;
|
||||||
|
import io.dataease.engine.utils.Utils;
|
||||||
|
import io.dataease.extensions.datasource.dto.DatasetTableFieldDTO;
|
||||||
|
import io.dataease.extensions.datasource.dto.DatasourceRequest;
|
||||||
|
import io.dataease.extensions.datasource.dto.DatasourceSchemaDTO;
|
||||||
|
import io.dataease.extensions.datasource.model.SQLMeta;
|
||||||
|
import io.dataease.extensions.datasource.provider.Provider;
|
||||||
|
import io.dataease.extensions.view.dto.*;
|
||||||
|
import io.dataease.extensions.view.util.ChartDataUtil;
|
||||||
|
import io.dataease.extensions.view.util.FieldUtil;
|
||||||
|
import io.dataease.utils.BeanUtils;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class SymbolicMapHandler extends GroupChartHandler {
|
||||||
|
@Resource
|
||||||
|
private DatasetDataManage datasetDataManage;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private String type = "symbolic-map";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AxisFormatResult formatAxis(ChartViewDTO view) {
|
||||||
|
var result = super.formatAxis(view);
|
||||||
|
result.getAxisMap().put(ChartAxis.extBubble, view.getExtBubble());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private Map<String, Object> customBuildResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, List<String[]> data, List<ChartViewFieldDTO> detailFields, List<String[]> detailData) {
|
||||||
|
var xAxis = formatResult.getAxisMap().get(ChartAxis.xAxis);
|
||||||
|
var extBubble = formatResult.getAxisMap().get(ChartAxis.extBubble);
|
||||||
|
var yAxis = formatResult.getAxisMap().get(ChartAxis.yAxis);
|
||||||
|
return ChartDataBuild.transSymbolicMapNormalWithDetail(view, xAxis, yAxis, extBubble, data, detailFields, detailData);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends ChartCalcDataResult> T calcChartResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, Map<String, Object> sqlMap, SQLMeta sqlMeta, Provider 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 extBubble = formatResult.getAxisMap().get(ChartAxis.extBubble);
|
||||||
|
var allFields = (List<ChartViewFieldDTO>) filterResult.getContext().get("allFields");
|
||||||
|
List<ChartViewFieldDTO> countField =chartViewManege.transFieldDTO(Collections.singletonList(chartViewManege.createCountField(view.getTableId())));
|
||||||
|
List<DatasetTableFieldDTO> datasetTableFieldDTOList = FieldUtil.transFields(allFields);
|
||||||
|
SQLMeta sqlMeta1 = new SQLMeta();
|
||||||
|
BeanUtils.copyBean(sqlMeta1, sqlMeta);
|
||||||
|
Dimension2SQLObj.dimension2sqlObj(sqlMeta, xAxis, datasetTableFieldDTOList, crossDs, dsMap, Utils.getParams(datasetTableFieldDTOList), view.getCalParams(), pluginManage);
|
||||||
|
List<ChartViewFieldDTO> yAxis = new ArrayList<>();
|
||||||
|
if(!extBubble.isEmpty() && !"*".equals(extBubble.get(0).getDataeaseName())){
|
||||||
|
yAxis.addAll(extBubble);
|
||||||
|
}
|
||||||
|
yAxis.addAll(countField);
|
||||||
|
datasetTableFieldDTOList.addAll(FieldUtil.transFields(countField));
|
||||||
|
formatResult.getAxisMap().put(ChartAxis.yAxis,countField);
|
||||||
|
Quota2SQLObj.quota2sqlObj(sqlMeta, yAxis, datasetTableFieldDTOList, crossDs, dsMap, Utils.getParams(datasetTableFieldDTOList), view.getCalParams(), pluginManage);
|
||||||
|
String querySql = SQLProvider.createQuerySQL(sqlMeta, true, needOrder, view);
|
||||||
|
querySql = provider.rebuildSQL(querySql, sqlMeta, crossDs, dsMap);
|
||||||
|
datasourceRequest.setQuery(querySql);
|
||||||
|
logger.debug("calcite chart sql: " + querySql);
|
||||||
|
List<String[]> data = (List<String[]>) provider.fetchResultField(datasourceRequest).get("data");
|
||||||
|
// 获取所有字段数据作为数据详情返回
|
||||||
|
List<String[]> detailData = new ArrayList<>();
|
||||||
|
List<Long> xAxisIds = xAxis.stream().map(ChartViewFieldDTO::getId).toList();
|
||||||
|
List<ChartViewFieldDTO> detailFields = new ArrayList<>();
|
||||||
|
detailFields.addAll(xAxis);
|
||||||
|
detailFields.addAll(allFields.stream().filter(field -> !xAxisIds.contains(field.getId())).toList());
|
||||||
|
if (ObjectUtils.isNotEmpty(detailFields)) {
|
||||||
|
List<DatasetTableFieldDTO> allFieldsTmp = FieldUtil.transFields(detailFields);
|
||||||
|
datasetDataManage.buildFieldName(sqlMap, allFieldsTmp);
|
||||||
|
String sql = (String) sqlMap.get("sql");
|
||||||
|
sql = Utils.replaceSchemaAlias(sql, dsMap);
|
||||||
|
SQLMeta sqlMeta2 = new SQLMeta();
|
||||||
|
Table2SQLObj.table2sqlobj(sqlMeta2, null, "(" + sql + ")", crossDs);
|
||||||
|
Field2SQLObj.field2sqlObj(sqlMeta2, allFieldsTmp, allFieldsTmp, crossDs, dsMap, Utils.getParams(allFieldsTmp), null, pluginManage);// todo chartParam从视图里取
|
||||||
|
String querySQL;
|
||||||
|
querySQL = SQLProvider.createQuerySQL(sqlMeta2, false, needOrder, false);
|
||||||
|
querySQL = provider.rebuildSQL(querySQL, sqlMeta2, crossDs, dsMap);
|
||||||
|
logger.debug("calcite data preview sql: " + querySQL);
|
||||||
|
// 调用数据源的calcite获得data
|
||||||
|
DatasourceRequest datasourceRequest1 = new DatasourceRequest();
|
||||||
|
datasourceRequest1.setQuery(querySQL);
|
||||||
|
datasourceRequest1.setDsList(dsMap);
|
||||||
|
detailData = (List<String[]>) provider.fetchResultField(datasourceRequest1).get("data");
|
||||||
|
}
|
||||||
|
//自定义排序
|
||||||
|
data = ChartDataUtil.resultCustomSort(xAxis, yAxis, view.getSortPriority(), data);
|
||||||
|
//数据重组逻辑可重载
|
||||||
|
var result = customBuildResult(view, formatResult, filterResult, data, detailFields, detailData);
|
||||||
|
T calcResult = (T) new ChartCalcDataResult();
|
||||||
|
calcResult.setData(result);
|
||||||
|
calcResult.setContext(filterResult.getContext());
|
||||||
|
calcResult.setQuerySql(querySql);
|
||||||
|
calcResult.setOriginData(data);
|
||||||
|
formatResult.getAxisMap().put(ChartAxis.yAxis,new ArrayList<>());
|
||||||
|
return calcResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChartViewDTO buildChart(ChartViewDTO view, ChartCalcDataResult calcResult, AxisFormatResult formatResult, CustomFilterResult filterResult) {
|
||||||
|
var desensitizationList = (Map<String, ColumnPermissionItem>) filterResult.getContext().get("desensitizationList");
|
||||||
|
var allFields = (List<ChartViewFieldDTO>) filterResult.getContext().get("allFields");
|
||||||
|
var xAxis = formatResult.getAxisMap().get(ChartAxis.xAxis);
|
||||||
|
var extBubble = formatResult.getAxisMap().get(ChartAxis.extBubble);
|
||||||
|
// 如果是表格导出查询 则在此处直接就可以返回
|
||||||
|
var extStack = formatResult.getAxisMap().get(ChartAxis.extStack);
|
||||||
|
if (view.getIsExcelExport()) {
|
||||||
|
Map<String, Object> sourceInfo = ChartDataBuild.transTableNormal(xAxis, extBubble, view, calcResult.getOriginData(), extStack, desensitizationList);
|
||||||
|
sourceInfo.put("sourceData", calcResult.getOriginData());
|
||||||
|
view.setData(sourceInfo);
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
// 图表组件可再扩展
|
||||||
|
Map<String, Object> mapTableNormal = calcResult.getData();
|
||||||
|
var drillFilters = filterResult.getFilterList().stream().filter(f -> f.getFilterType() == 1).collect(Collectors.toList());
|
||||||
|
var isDrill = CollectionUtils.isNotEmpty(drillFilters);
|
||||||
|
// 构建结果
|
||||||
|
Map<String, Object> dataMap = new TreeMap<>();
|
||||||
|
dataMap.putAll(calcResult.getData());
|
||||||
|
dataMap.putAll(mapTableNormal);
|
||||||
|
dataMap.put("sourceFields", allFields);
|
||||||
|
mergeAssistField(calcResult.getDynamicAssistFields(), calcResult.getAssistData());
|
||||||
|
dataMap.put("dynamicAssistLines", calcResult.getDynamicAssistFields());
|
||||||
|
view.setData(dataMap);
|
||||||
|
view.setSql(Base64.getEncoder().encodeToString(calcResult.getQuerySql().getBytes()));
|
||||||
|
view.setDrill(isDrill);
|
||||||
|
view.setDrillFilters(drillFilters);
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
package io.dataease.chart.charts.impl.mix;
|
||||||
|
|
||||||
|
import io.dataease.chart.utils.ChartDataBuild;
|
||||||
|
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.CustomFilterResult;
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class DualLineMixHandler extends GroupMixHandler {
|
||||||
|
@Getter
|
||||||
|
private final String type = "chart-mix-dual-line";
|
||||||
|
|
||||||
|
@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.transMixChartDataAntV(xAxisBase, xAxis, xAxisExt, yAxis, view, data, isDrill, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,52 @@
|
|||||||
|
package io.dataease.chart.charts.impl.mix;
|
||||||
|
|
||||||
|
import io.dataease.extensions.view.dto.*;
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class GroupMixHandler extends MixHandler {
|
||||||
|
@Getter
|
||||||
|
private final String type = "chart-mix-group";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AxisFormatResult formatAxis(ChartViewDTO view) {
|
||||||
|
var axisMap = new HashMap<ChartAxis, List<ChartViewFieldDTO>>();
|
||||||
|
var context = new HashMap<String, Object>();
|
||||||
|
AxisFormatResult result = new AxisFormatResult(axisMap, context);
|
||||||
|
//左轴分组子维度,非分组不需要
|
||||||
|
axisMap.put(ChartAxis.xAxisExt, view.getXAxisExt());
|
||||||
|
//左轴堆叠子维度,非堆叠不需要
|
||||||
|
axisMap.put(ChartAxis.extStack, Collections.emptyList());
|
||||||
|
//左轴指标
|
||||||
|
axisMap.put(ChartAxis.yAxis, view.getYAxis());
|
||||||
|
//右轴分组子维度
|
||||||
|
axisMap.put(ChartAxis.extBubble, view.getExtBubble());
|
||||||
|
//右轴指标
|
||||||
|
axisMap.put(ChartAxis.yAxisExt, view.getYAxisExt());
|
||||||
|
//去除除了x轴以外的排序
|
||||||
|
axisMap.forEach((k, v) -> {
|
||||||
|
if (!ChartAxis.xAxisExt.equals(k)) {
|
||||||
|
v.forEach(x -> x.setSort("none"));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
axisMap.put(ChartAxis.extLabel, view.getExtLabel());
|
||||||
|
axisMap.put(ChartAxis.extTooltip, view.getExtTooltip());
|
||||||
|
//图表整体主维度
|
||||||
|
var xAxis = new ArrayList<>(view.getXAxis());
|
||||||
|
var xAxisGroup = new ArrayList<>(view.getXAxis());
|
||||||
|
xAxisGroup.addAll(view.getXAxisExt());
|
||||||
|
axisMap.put(ChartAxis.xAxis, xAxisGroup);
|
||||||
|
context.put("xAxisBase", xAxis);
|
||||||
|
axisMap.put(ChartAxis.drill, new ArrayList<>(view.getDrillFields()));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> buildNormalResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, List<String[]> data) {
|
||||||
|
return super.buildNormalResult(view, formatResult, filterResult, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,212 @@
|
|||||||
|
package io.dataease.chart.charts.impl.mix;
|
||||||
|
|
||||||
|
import io.dataease.chart.charts.impl.YoyChartHandler;
|
||||||
|
import io.dataease.chart.utils.ChartDataBuild;
|
||||||
|
import io.dataease.engine.utils.Utils;
|
||||||
|
import io.dataease.extensions.datasource.dto.DatasourceRequest;
|
||||||
|
import io.dataease.extensions.datasource.dto.DatasourceSchemaDTO;
|
||||||
|
import io.dataease.extensions.datasource.model.SQLMeta;
|
||||||
|
import io.dataease.extensions.datasource.provider.Provider;
|
||||||
|
import io.dataease.extensions.view.dto.*;
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class MixHandler extends YoyChartHandler {
|
||||||
|
@Getter
|
||||||
|
private final String type = "chart-mix";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AxisFormatResult formatAxis(ChartViewDTO view) {
|
||||||
|
var axisMap = new HashMap<ChartAxis, List<ChartViewFieldDTO>>();
|
||||||
|
var context = new HashMap<String, Object>();
|
||||||
|
AxisFormatResult result = new AxisFormatResult(axisMap, context);
|
||||||
|
//左轴分组子维度,非分组不需要
|
||||||
|
axisMap.put(ChartAxis.xAxisExt, Collections.emptyList());
|
||||||
|
//左轴堆叠子维度,非堆叠不需要
|
||||||
|
axisMap.put(ChartAxis.extStack, Collections.emptyList());
|
||||||
|
//左轴指标
|
||||||
|
axisMap.put(ChartAxis.yAxis, view.getYAxis());
|
||||||
|
//右轴分组子维度
|
||||||
|
axisMap.put(ChartAxis.extBubble, view.getExtBubble());
|
||||||
|
//右轴指标
|
||||||
|
axisMap.put(ChartAxis.yAxisExt, view.getYAxisExt());
|
||||||
|
//去除除了x轴以外的排序
|
||||||
|
axisMap.forEach((k, v) -> {
|
||||||
|
v.forEach(x -> x.setSort("none"));
|
||||||
|
});
|
||||||
|
axisMap.put(ChartAxis.extLabel, view.getExtLabel());
|
||||||
|
axisMap.put(ChartAxis.extTooltip, view.getExtTooltip());
|
||||||
|
//图表整体主维度
|
||||||
|
axisMap.put(ChartAxis.xAxis, new ArrayList<>(view.getXAxis()));
|
||||||
|
context.put("xAxisBase", new ArrayList<>(view.getXAxis()));
|
||||||
|
axisMap.put(ChartAxis.drill, new ArrayList<>(view.getDrillFields()));
|
||||||
|
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);
|
||||||
|
if (StringUtils.equals((String) formatResult.getContext().get("isRight"), "isRight")) {
|
||||||
|
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.transMixChartDataAntV(xAxisBase, xAxis, xAxisExt, yAxis, view, data, isDrill, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
var xAxisBase = (List<ChartViewFieldDTO>) formatResult.getContext().get("xAxisBase");
|
||||||
|
var yAxis = formatResult.getAxisMap().get(ChartAxis.yAxis);
|
||||||
|
var xAxis = formatResult.getAxisMap().get(ChartAxis.xAxis);
|
||||||
|
var xAxisExt = formatResult.getAxisMap().get(ChartAxis.xAxisExt);
|
||||||
|
var result = ChartDataBuild.transMixChartDataAntV(xAxisBase, xAxis, xAxisExt, yAxis, view, data, isDrill, false);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends ChartCalcDataResult> T calcChartResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, Map<String, Object> sqlMap, SQLMeta sqlMeta, Provider provider) {
|
||||||
|
//计算左轴, 包含 xAxis, yAxis
|
||||||
|
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 leftResult = (T) super.calcChartResult(view, formatResult, filterResult, sqlMap, sqlMeta, provider);
|
||||||
|
var dynamicAssistFields = getDynamicAssistFields(view);
|
||||||
|
try {
|
||||||
|
//如果有同环比过滤,应该用原始sql
|
||||||
|
var originSql = leftResult.getQuerySql();
|
||||||
|
var leftAssistFields = dynamicAssistFields.stream().filter(x -> StringUtils.equalsAnyIgnoreCase(x.getYAxisType(), "left")).toList();
|
||||||
|
var yAxis = formatResult.getAxisMap().get(ChartAxis.yAxis);
|
||||||
|
var assistFields = getAssistFields(leftAssistFields, yAxis);
|
||||||
|
if (CollectionUtils.isNotEmpty(assistFields)) {
|
||||||
|
var req = new DatasourceRequest();
|
||||||
|
req.setDsList(dsMap);
|
||||||
|
var assistSql = assistSQL(originSql, assistFields, dsMap);
|
||||||
|
req.setQuery(assistSql);
|
||||||
|
logger.debug("calcite assistSql sql: " + assistSql);
|
||||||
|
var assistData = (List<String[]>) provider.fetchResultField(req).get("data");
|
||||||
|
leftResult.setAssistData(assistData);
|
||||||
|
leftResult.setDynamicAssistFields(leftAssistFields);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
AxisFormatResult formatResult2 = new AxisFormatResult();
|
||||||
|
var axisMap = new HashMap<ChartAxis, List<ChartViewFieldDTO>>();
|
||||||
|
axisMap.put(ChartAxis.extLabel, new ArrayList<>(formatResult.getAxisMap().get(ChartAxis.extLabel)));
|
||||||
|
axisMap.put(ChartAxis.extTooltip, new ArrayList<>(formatResult.getAxisMap().get(ChartAxis.extTooltip)));
|
||||||
|
axisMap.put(ChartAxis.drill, new ArrayList<>(formatResult.getAxisMap().get(ChartAxis.drill)));
|
||||||
|
formatResult2.setAxisMap(axisMap);
|
||||||
|
formatResult2.setContext(formatResult.getContext());
|
||||||
|
|
||||||
|
// 计算右轴,包含 xAxis,xAxisExt,yAxisExt,需要去掉 group 和 stack
|
||||||
|
var xAxis = new ArrayList<>(view.getXAxis());
|
||||||
|
var extBubble = new ArrayList<>(formatResult.getAxisMap().get(ChartAxis.extBubble));
|
||||||
|
xAxis.addAll(extBubble);
|
||||||
|
var dillAxis = (ArrayList<ChartViewFieldDTO>) formatResult.getContext().get("dillAxis");
|
||||||
|
var fields = xAxis.stream().map(ChartViewFieldDTO::getId).collect(Collectors.toSet());
|
||||||
|
for (ChartViewFieldDTO dillAxi : dillAxis) {
|
||||||
|
if (!fields.contains(dillAxi.getId())) {
|
||||||
|
xAxis.add(dillAxi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
formatResult2.getAxisMap().put(ChartAxis.xAxis, xAxis);
|
||||||
|
formatResult2.getAxisMap().put(ChartAxis.xAxisExt, extBubble);
|
||||||
|
var yAxisExt = new ArrayList<>(formatResult.getAxisMap().get(ChartAxis.yAxisExt));
|
||||||
|
formatResult2.getAxisMap().put(ChartAxis.yAxis, yAxisExt);
|
||||||
|
formatResult2.getContext().remove("yoyFiltered");
|
||||||
|
formatResult2.getContext().put("isRight", "isRight");
|
||||||
|
|
||||||
|
|
||||||
|
formatResult.getContext().put("subAxisMap", axisMap);
|
||||||
|
|
||||||
|
// 右轴重新检测同环比过滤
|
||||||
|
customFilter(view, filterResult.getFilterList(), formatResult2);
|
||||||
|
var rightResult = (T) super.calcChartResult(view, formatResult2, filterResult, sqlMap, sqlMeta, provider);
|
||||||
|
try {
|
||||||
|
//如果有同环比过滤,应该用原始sql
|
||||||
|
var originSql = rightResult.getQuerySql();
|
||||||
|
var rightAssistFields = dynamicAssistFields.stream().filter(x -> StringUtils.equalsAnyIgnoreCase(x.getYAxisType(), "right")).toList();
|
||||||
|
var yAxis = formatResult2.getAxisMap().get(ChartAxis.yAxis);
|
||||||
|
var assistFields = getAssistFields(rightAssistFields, yAxis);
|
||||||
|
if (CollectionUtils.isNotEmpty(assistFields)) {
|
||||||
|
var req = new DatasourceRequest();
|
||||||
|
req.setDsList(dsMap);
|
||||||
|
var assistSql = assistSQL(originSql, assistFields, dsMap);
|
||||||
|
req.setQuery(assistSql);
|
||||||
|
var assistData = (List<String[]>) provider.fetchResultField(req).get("data");
|
||||||
|
rightResult.setAssistData(assistData);
|
||||||
|
rightResult.setDynamicAssistFields(rightAssistFields);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
var mixResult = (T) new ChartCalcDataResult();
|
||||||
|
var data = new HashMap<String, Object>();
|
||||||
|
data.put("left", leftResult);
|
||||||
|
data.put("right", rightResult);
|
||||||
|
mixResult.setData(data);
|
||||||
|
mixResult.setContext(filterResult.getContext());
|
||||||
|
return mixResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChartViewDTO buildChart(ChartViewDTO view, ChartCalcDataResult calcResult, AxisFormatResult formatResult, CustomFilterResult filterResult) {
|
||||||
|
var desensitizationList = (Map<String, ColumnPermissionItem>) filterResult.getContext().get("desensitizationList");
|
||||||
|
var leftCalcResult = (ChartCalcDataResult) calcResult.getData().get("left");
|
||||||
|
var leftFields = new ArrayList<ChartViewFieldDTO>();
|
||||||
|
leftFields.addAll(formatResult.getAxisMap().get(ChartAxis.xAxis));
|
||||||
|
leftFields.addAll(formatResult.getAxisMap().get(ChartAxis.yAxis));
|
||||||
|
mergeAssistField(leftCalcResult.getDynamicAssistFields(), leftCalcResult.getAssistData());
|
||||||
|
var leftOriginData = leftCalcResult.getOriginData();
|
||||||
|
var leftTable = ChartDataBuild.transTableNormal(leftFields, view, leftOriginData, desensitizationList);
|
||||||
|
var leftData = new HashMap<String, Object>(leftTable);
|
||||||
|
leftData.putAll(leftCalcResult.getData());
|
||||||
|
leftData.put("dynamicAssistLines", leftCalcResult.getDynamicAssistFields());
|
||||||
|
|
||||||
|
var rightCalcResult = (ChartCalcDataResult) calcResult.getData().get("right");
|
||||||
|
var rightFields = new ArrayList<ChartViewFieldDTO>();
|
||||||
|
|
||||||
|
var subAxisMap = (HashMap<ChartAxis, List<ChartViewFieldDTO>>) formatResult.getContext().get("subAxisMap");
|
||||||
|
rightFields.addAll(subAxisMap.get(ChartAxis.xAxis));
|
||||||
|
rightFields.addAll(subAxisMap.get(ChartAxis.yAxis));
|
||||||
|
|
||||||
|
mergeAssistField(rightCalcResult.getDynamicAssistFields(), rightCalcResult.getAssistData());
|
||||||
|
var rightOriginData = rightCalcResult.getOriginData();
|
||||||
|
var rightTable = ChartDataBuild.transTableNormal(rightFields, view, rightOriginData, desensitizationList);
|
||||||
|
var rightData = new HashMap<String, Object>(rightTable);
|
||||||
|
rightData.putAll(rightCalcResult.getData());
|
||||||
|
rightData.put("dynamicAssistLines", rightCalcResult.getDynamicAssistFields());
|
||||||
|
|
||||||
|
// 构建结果
|
||||||
|
Map<String, Object> chartData = new TreeMap<>();
|
||||||
|
chartData.put("left", leftData);
|
||||||
|
chartData.put("right", rightData);
|
||||||
|
|
||||||
|
var drillFilters = filterResult.getFilterList().stream().filter(f -> f.getFilterType() == 1).collect(Collectors.toList());
|
||||||
|
// 日期下钻替换回去
|
||||||
|
drillFilters.forEach(f -> {
|
||||||
|
if (CollectionUtils.isNotEmpty(f.getOriginValue())) {
|
||||||
|
f.setValue(f.getOriginValue());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var isDrill = CollectionUtils.isNotEmpty(drillFilters);
|
||||||
|
view.setDrillFilters(drillFilters);
|
||||||
|
view.setDrill(isDrill);
|
||||||
|
view.setSql(leftCalcResult.getQuerySql());
|
||||||
|
view.setData(chartData);
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,72 @@
|
|||||||
|
package io.dataease.chart.charts.impl.mix;
|
||||||
|
|
||||||
|
import io.dataease.chart.utils.ChartDataBuild;
|
||||||
|
import io.dataease.extensions.view.dto.*;
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class StackMixHandler extends MixHandler {
|
||||||
|
@Getter
|
||||||
|
private final String type = "chart-mix-stack";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AxisFormatResult formatAxis(ChartViewDTO view) {
|
||||||
|
var axisMap = new HashMap<ChartAxis, List<ChartViewFieldDTO>>();
|
||||||
|
var context = new HashMap<String, Object>();
|
||||||
|
AxisFormatResult result = new AxisFormatResult(axisMap, context);
|
||||||
|
//左轴分组子维度,非分组不需要
|
||||||
|
axisMap.put(ChartAxis.xAxisExt, Collections.emptyList());
|
||||||
|
//左轴堆叠子维度,非堆叠不需要
|
||||||
|
axisMap.put(ChartAxis.extStack, view.getExtStack());
|
||||||
|
//左轴指标
|
||||||
|
axisMap.put(ChartAxis.yAxis, view.getYAxis());
|
||||||
|
//右轴分组子维度
|
||||||
|
axisMap.put(ChartAxis.extBubble, view.getExtBubble());
|
||||||
|
//右轴指标
|
||||||
|
axisMap.put(ChartAxis.yAxisExt, view.getYAxisExt());
|
||||||
|
//去除除了x轴以外的排序
|
||||||
|
axisMap.forEach((k, v) -> {
|
||||||
|
if (!ChartAxis.extStack.equals(k)) {
|
||||||
|
v.forEach(x -> x.setSort("none"));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
axisMap.put(ChartAxis.extLabel, view.getExtLabel());
|
||||||
|
axisMap.put(ChartAxis.extTooltip, view.getExtTooltip());
|
||||||
|
//图表整体主维度
|
||||||
|
var xAxis = new ArrayList<>(view.getXAxis());
|
||||||
|
var xAxisStack = new ArrayList<>(view.getXAxis());
|
||||||
|
xAxisStack.addAll(view.getExtStack());
|
||||||
|
axisMap.put(ChartAxis.xAxis, xAxisStack);
|
||||||
|
context.put("xAxisBase", xAxis);
|
||||||
|
axisMap.put(ChartAxis.drill, new ArrayList<>(view.getDrillFields()));
|
||||||
|
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 extStack = formatResult.getAxisMap().get(ChartAxis.extStack);
|
||||||
|
var yAxis = formatResult.getAxisMap().get(ChartAxis.yAxis);
|
||||||
|
if (CollectionUtils.isNotEmpty(extStack)) {
|
||||||
|
// 堆叠左轴
|
||||||
|
var xAxis = formatResult.getAxisMap().get(ChartAxis.xAxis);
|
||||||
|
var drillAxis = xAxis.stream().filter(axis -> FieldSource.DRILL == axis.getSource()).toList();
|
||||||
|
var xAxisBase = xAxis.subList(0, xAxis.size() - extStack.size() - drillAxis.size());
|
||||||
|
//var xAxisBase = (List<ChartViewFieldDTO>) formatResult.getContext().get("xAxisBase");
|
||||||
|
return ChartDataBuild.transMixChartStackDataAntV(xAxisBase, xAxis, extStack, yAxis, view, data, isDrill);
|
||||||
|
} else {
|
||||||
|
//无堆叠左轴和右轴还是走原逻辑
|
||||||
|
var xAxisBase = (List<ChartViewFieldDTO>) formatResult.getContext().get("xAxisBase");
|
||||||
|
var xAxis = formatResult.getAxisMap().get(ChartAxis.xAxis);
|
||||||
|
var xAxisExt = formatResult.getAxisMap().get(ChartAxis.xAxisExt);
|
||||||
|
return super.buildNormalResult(view, formatResult, filterResult, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
package io.dataease.chart.charts.impl.numeric;
|
||||||
|
|
||||||
|
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 NumericalChartHandler {
|
||||||
|
@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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,65 @@
|
|||||||
|
package io.dataease.chart.charts.impl.numeric;
|
||||||
|
|
||||||
|
import io.dataease.chart.charts.impl.YoyChartHandler;
|
||||||
|
import io.dataease.chart.utils.ChartDataBuild;
|
||||||
|
import io.dataease.extensions.datasource.model.SQLMeta;
|
||||||
|
import io.dataease.extensions.datasource.provider.Provider;
|
||||||
|
import io.dataease.extensions.view.dto.*;
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class IndicatorHandler extends YoyChartHandler {
|
||||||
|
@Getter
|
||||||
|
private String render = "custom";
|
||||||
|
@Getter
|
||||||
|
private String type = "indicator";
|
||||||
|
|
||||||
|
@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.transNormalChartData(xAxis, yAxis, view, data, isDrill);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends ChartCalcDataResult> T calcChartResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, Map<String, Object> sqlMap, SQLMeta sqlMeta, Provider provider) {
|
||||||
|
this.setIndicatorHandlerXAxis(formatResult, filterResult);
|
||||||
|
return (T) super.calcChartResult(view, formatResult, filterResult, sqlMap, sqlMeta, provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AxisFormatResult formatAxis(ChartViewDTO view) {
|
||||||
|
var axisMap = new HashMap<ChartAxis, List<ChartViewFieldDTO>>();
|
||||||
|
var yAxis = new ArrayList<>(view.getYAxis());
|
||||||
|
axisMap.put(ChartAxis.xAxis, new ArrayList<>());
|
||||||
|
axisMap.put(ChartAxis.yAxis, yAxis);
|
||||||
|
var context = new HashMap<String, Object>();
|
||||||
|
return new AxisFormatResult(axisMap, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setIndicatorHandlerXAxis(AxisFormatResult formatResult, CustomFilterResult filterResult) {
|
||||||
|
var xAxis = formatResult.getAxisMap().get(ChartAxis.xAxis);
|
||||||
|
var yAxis = formatResult.getAxisMap().get(ChartAxis.yAxis);
|
||||||
|
var allFields = (List<ChartViewFieldDTO>) filterResult.getContext().get("allFields");
|
||||||
|
ChartViewFieldDTO yAxisChartViewFieldDTO = yAxis.get(0);
|
||||||
|
ChartFieldCompareDTO compareCalc = yAxisChartViewFieldDTO.getCompareCalc();
|
||||||
|
boolean isYoy = org.apache.commons.lang3.StringUtils.isNotEmpty(compareCalc.getType())
|
||||||
|
&& !org.apache.commons.lang3.StringUtils.equalsIgnoreCase(compareCalc.getType(), "none");
|
||||||
|
if (isYoy) {
|
||||||
|
xAxis.clear();
|
||||||
|
// 设置维度字段,从同环比中获取用户选择的字段
|
||||||
|
xAxis.addAll(allFields.stream().filter(i -> org.springframework.util.StringUtils.endsWithIgnoreCase(i.getId().toString(), compareCalc.getField().toString())).toList());
|
||||||
|
xAxis.get(0).setSort("desc");
|
||||||
|
if(Objects.isNull(compareCalc.getCustom())){
|
||||||
|
xAxis.get(0).setDateStyle("y_M_d");
|
||||||
|
}else{
|
||||||
|
xAxis.get(0).setDateStyle(compareCalc.getCustom().getTimeType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
formatResult.getAxisMap().put(ChartAxis.xAxis, xAxis);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
package io.dataease.chart.charts.impl.numeric;
|
||||||
|
|
||||||
|
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 NumericalChartHandler {
|
||||||
|
@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;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,85 @@
|
|||||||
|
package io.dataease.chart.charts.impl.numeric;
|
||||||
|
|
||||||
|
import io.dataease.chart.charts.impl.DefaultChartHandler;
|
||||||
|
import io.dataease.chart.utils.ChartDataBuild;
|
||||||
|
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.datasource.dto.DatasetTableFieldDTO;
|
||||||
|
import io.dataease.extensions.datasource.dto.DatasourceRequest;
|
||||||
|
import io.dataease.extensions.datasource.dto.DatasourceSchemaDTO;
|
||||||
|
import io.dataease.extensions.datasource.model.SQLMeta;
|
||||||
|
import io.dataease.extensions.datasource.provider.Provider;
|
||||||
|
import io.dataease.extensions.view.dto.*;
|
||||||
|
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 java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class NumericalChartHandler extends DefaultChartHandler {
|
||||||
|
@Override
|
||||||
|
public <T extends ChartCalcDataResult> T calcChartResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, Map<String, Object> sqlMap, SQLMeta sqlMeta, Provider 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 = (List<ChartViewFieldDTO>) filterResult.getContext().get("allFields");
|
||||||
|
Quota2SQLObj.quota2sqlObj(sqlMeta, yAxis, FieldUtil.transFields(allFields), crossDs, dsMap, Utils.getParams(FieldUtil.transFields(allFields)), view.getCalParams(), pluginManage);
|
||||||
|
String querySql = SQLProvider.createQuerySQL(sqlMeta, true, needOrder, view);
|
||||||
|
querySql = provider.rebuildSQL(querySql, sqlMeta, crossDs, dsMap);
|
||||||
|
datasourceRequest.setQuery(querySql);
|
||||||
|
logger.debug("calcite chart sql: " + 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);
|
||||||
|
if (maxField.get("id") == null || StringUtils.isEmpty(maxField.get("id").toString())) {
|
||||||
|
DEException.throwException(Translator.get("i18n_gauge_field_delete"));
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
@ -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";
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
package io.dataease.chart.charts.impl.others;
|
||||||
|
|
||||||
|
import io.dataease.chart.charts.impl.YoyChartHandler;
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class RichTextHandler extends YoyChartHandler {
|
||||||
|
@Getter
|
||||||
|
private String type = "rich-text";
|
||||||
|
@Getter
|
||||||
|
private String render = "custom";
|
||||||
|
}
|
@ -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";
|
||||||
|
}
|
@ -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 TreemapHandler extends ExtQuotaChartHandler {
|
||||||
|
@Getter
|
||||||
|
private String type = "treemap";
|
||||||
|
}
|
@ -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";
|
||||||
|
}
|
@ -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";
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
package io.dataease.chart.charts.impl.pie;
|
||||||
|
|
||||||
|
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-donut-rose", 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;
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
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.Iterator;
|
||||||
|
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 yAxisTemp = new ArrayList<>(yAxis);
|
||||||
|
var extBubble = formatResult.getAxisMap().get(ChartAxis.extBubble);
|
||||||
|
if (!extBubble.isEmpty()) {
|
||||||
|
// 剔除气泡大小,移除一个
|
||||||
|
Iterator<ChartViewFieldDTO> iterator = yAxisTemp.iterator();
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
ChartViewFieldDTO obj = iterator.next();
|
||||||
|
if (obj.getId().equals(extBubble.getFirst().getId())) {
|
||||||
|
iterator.remove();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Map<String, Object> result = ChartDataBuild.transScatterDataAntV(xAxis, yAxisTemp, view, data, extBubble, isDrill);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,83 @@
|
|||||||
|
package io.dataease.chart.charts.impl.table;
|
||||||
|
|
||||||
|
import io.dataease.chart.charts.impl.DefaultChartHandler;
|
||||||
|
import io.dataease.chart.utils.ChartDataBuild;
|
||||||
|
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.datasource.dto.DatasourceRequest;
|
||||||
|
import io.dataease.extensions.datasource.dto.DatasourceSchemaDTO;
|
||||||
|
import io.dataease.extensions.datasource.model.SQLMeta;
|
||||||
|
import io.dataease.extensions.datasource.provider.Provider;
|
||||||
|
import io.dataease.extensions.view.dto.*;
|
||||||
|
import io.dataease.extensions.view.util.ChartDataUtil;
|
||||||
|
import io.dataease.extensions.view.util.FieldUtil;
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class TableHeatmapHandler extends DefaultChartHandler {
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private String type = "t-heatmap";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AxisFormatResult formatAxis(ChartViewDTO view) {
|
||||||
|
var result = super.formatAxis(view);
|
||||||
|
var xAxis = new ArrayList<ChartViewFieldDTO>(view.getXAxis());
|
||||||
|
xAxis.addAll(view.getXAxisExt());
|
||||||
|
var yAxis = new ArrayList<ChartViewFieldDTO>(view.getYAxis());
|
||||||
|
yAxis.addAll(view.getExtColor());
|
||||||
|
result.getAxisMap().put(ChartAxis.xAxis, xAxis);
|
||||||
|
result.getAxisMap().put(ChartAxis.yAxis, yAxis);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, Object> buildResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, List<String[]> data) {
|
||||||
|
var xAxis = formatResult.getAxisMap().get(ChartAxis.xAxis);
|
||||||
|
Map<String, Object> result = ChartDataBuild.transChartData( xAxis, new ArrayList<>(), view, data, false);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends ChartCalcDataResult> T calcChartResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, Map<String, Object> sqlMap, SQLMeta sqlMeta, Provider 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 = (List<ChartViewFieldDTO>) filterResult.getContext().get("allFields");
|
||||||
|
Dimension2SQLObj.dimension2sqlObj(sqlMeta, xAxis, FieldUtil.transFields(allFields), crossDs, dsMap, Utils.getParams(FieldUtil.transFields(allFields)), view.getCalParams(), pluginManage);
|
||||||
|
Quota2SQLObj.quota2sqlObj(sqlMeta, yAxis, FieldUtil.transFields(allFields), crossDs, dsMap, Utils.getParams(FieldUtil.transFields(allFields)), view.getCalParams(), pluginManage);
|
||||||
|
String querySql = SQLProvider.createQuerySQL(sqlMeta, true, needOrder, view);
|
||||||
|
querySql = provider.rebuildSQL(querySql, sqlMeta, crossDs, dsMap);
|
||||||
|
datasourceRequest.setQuery(querySql);
|
||||||
|
logger.debug("calcite chart sql: " + querySql);
|
||||||
|
List<String[]> data = (List<String[]>) provider.fetchResultField(datasourceRequest).get("data");
|
||||||
|
//自定义排序
|
||||||
|
data = ChartDataUtil.resultCustomSort(xAxis, yAxis, view.getSortPriority(), 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,165 @@
|
|||||||
|
package io.dataease.chart.charts.impl.table;
|
||||||
|
|
||||||
|
import io.dataease.api.chart.dto.PageInfo;
|
||||||
|
import io.dataease.chart.charts.impl.DefaultChartHandler;
|
||||||
|
import io.dataease.engine.sql.SQLProvider;
|
||||||
|
import io.dataease.engine.trans.Dimension2SQLObj;
|
||||||
|
import io.dataease.engine.utils.Utils;
|
||||||
|
import io.dataease.extensions.datasource.dto.DatasourceRequest;
|
||||||
|
import io.dataease.extensions.datasource.dto.DatasourceSchemaDTO;
|
||||||
|
import io.dataease.extensions.datasource.model.SQLMeta;
|
||||||
|
import io.dataease.extensions.datasource.provider.Provider;
|
||||||
|
import io.dataease.extensions.view.dto.*;
|
||||||
|
import io.dataease.extensions.view.util.ChartDataUtil;
|
||||||
|
import io.dataease.extensions.view.util.FieldUtil;
|
||||||
|
import io.dataease.utils.BeanUtils;
|
||||||
|
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.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@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> T customFilter(ChartViewDTO view, List<ChartExtFilterDTO> filterList, AxisFormatResult 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")) {
|
||||||
|
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 (T) new CustomFilterResult(filterList, formatResult.getContext());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends ChartCalcDataResult> T calcChartResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, Map<String, Object> sqlMap, SQLMeta sqlMeta, Provider 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 crossDs = Utils.isCrossDs(dsMap);
|
||||||
|
DatasourceRequest datasourceRequest = new DatasourceRequest();
|
||||||
|
datasourceRequest.setDsList(dsMap);
|
||||||
|
var xAxis = formatResult.getAxisMap().get(ChartAxis.xAxis);
|
||||||
|
var allFields = (List<ChartViewFieldDTO>) filterResult.getContext().get("allFields");
|
||||||
|
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, Utils.getParams(FieldUtil.transFields(allFields)), view.getCalParams(), pluginManage);
|
||||||
|
if (view.getIsExcelExport()) {
|
||||||
|
for (int i = 0; i < xAxis.size(); i++) {
|
||||||
|
ChartViewFieldDTO fieldDTO = null;
|
||||||
|
for (ChartViewFieldDTO allField : allFields) {
|
||||||
|
if (allField.getId().equals(xAxis.get(i).getId())) {
|
||||||
|
fieldDTO = allField;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fieldDTO != null && fieldDTO.isAgg()) {
|
||||||
|
sqlMeta.getXFields().get(i).setFieldName("'-'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String originSql = SQLProvider.createQuerySQL(sqlMeta, false, !StringUtils.equalsIgnoreCase(dsMap.entrySet().iterator().next().getValue().getType(), "es"), view);// 明细表强制加排序
|
||||||
|
String limit = ((pageInfo.getGoPage() != null && pageInfo.getPageSize() != null) ? " LIMIT " + pageInfo.getPageSize() + " OFFSET " + (pageInfo.getGoPage() - 1) * chartExtRequest.getPageSize() : "");
|
||||||
|
var querySql = originSql + limit;
|
||||||
|
|
||||||
|
var tablePageMode = (String) filterResult.getContext().get("tablePageMode");
|
||||||
|
var totalPageSql = "SELECT COUNT(*) FROM (" + SQLProvider.createQuerySQLNoSort(sqlMeta, false, view) + ") COUNT_TEMP";
|
||||||
|
if (StringUtils.isNotEmpty(totalPageSql) && StringUtils.equalsIgnoreCase(tablePageMode, "page")) {
|
||||||
|
totalPageSql = provider.rebuildSQL(totalPageSql, sqlMeta, crossDs, dsMap);
|
||||||
|
datasourceRequest.setQuery(totalPageSql);
|
||||||
|
datasourceRequest.setTotalPageFlag(true);
|
||||||
|
logger.debug("calcite total sql: " + totalPageSql);
|
||||||
|
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 = provider.rebuildSQL(querySql, sqlMeta, crossDs, dsMap);
|
||||||
|
datasourceRequest.setQuery(querySql);
|
||||||
|
logger.debug("calcite chart sql: " + querySql);
|
||||||
|
List<String[]> data = (List<String[]>) provider.fetchResultField(datasourceRequest).get("data");
|
||||||
|
//自定义排序
|
||||||
|
data = ChartDataUtil.resultCustomSort(xAxis, Collections.emptyList(), view.getSortPriority(), 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);
|
||||||
|
try {
|
||||||
|
var dynamicAssistFields = getDynamicThresholdFields(view);
|
||||||
|
Set<Long> fieldIds = xAxis.stream().map(ChartViewFieldDTO::getId).collect(Collectors.toSet());
|
||||||
|
List<ChartViewFieldDTO> finalXAxis = xAxis;
|
||||||
|
dynamicAssistFields.forEach(i -> {
|
||||||
|
if (!fieldIds.contains(i.getFieldId())) {
|
||||||
|
ChartViewFieldDTO fieldDTO = new ChartViewFieldDTO();
|
||||||
|
BeanUtils.copyBean(fieldDTO, i.getCurField());
|
||||||
|
finalXAxis.add(fieldDTO);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var yAxis = formatResult.getAxisMap().get(ChartAxis.yAxis);
|
||||||
|
var assistFields = getAssistFields(dynamicAssistFields, yAxis, xAxis);
|
||||||
|
if (CollectionUtils.isNotEmpty(assistFields)) {
|
||||||
|
var req = new DatasourceRequest();
|
||||||
|
req.setDsList(dsMap);
|
||||||
|
var assistSql = assistSQL(querySql, assistFields, dsMap);
|
||||||
|
req.setQuery(assistSql);
|
||||||
|
logger.debug("calcite assistSql sql: " + assistSql);
|
||||||
|
var assistData = (List<String[]>) provider.fetchResultField(req).get("data");
|
||||||
|
calcResult.setAssistData(assistData);
|
||||||
|
calcResult.setDynamicAssistFields(dynamicAssistFields);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return calcResult;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
package io.dataease.chart.charts.impl.table;
|
||||||
|
|
||||||
|
import io.dataease.chart.charts.impl.YoyChartHandler;
|
||||||
|
import io.dataease.extensions.datasource.dto.DatasourceRequest;
|
||||||
|
import io.dataease.extensions.datasource.dto.DatasourceSchemaDTO;
|
||||||
|
import io.dataease.extensions.datasource.model.SQLMeta;
|
||||||
|
import io.dataease.extensions.datasource.provider.Provider;
|
||||||
|
import io.dataease.extensions.view.dto.*;
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author jianneng
|
||||||
|
* @date 2024/9/11 11:37
|
||||||
|
**/
|
||||||
|
@Component
|
||||||
|
public class TableNormalHandler extends YoyChartHandler {
|
||||||
|
@Getter
|
||||||
|
private String type = "table-normal";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends ChartCalcDataResult> T calcChartResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, Map<String, Object> sqlMap, SQLMeta sqlMeta, Provider provider) {
|
||||||
|
var dsMap = (Map<Long, DatasourceSchemaDTO>) sqlMap.get("dsMap");
|
||||||
|
var result = (T) super.calcChartResult(view, formatResult, filterResult, sqlMap, sqlMeta, provider);
|
||||||
|
try {
|
||||||
|
var originSql = result.getQuerySql();
|
||||||
|
var dynamicAssistFields = getDynamicThresholdFields(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, dsMap);
|
||||||
|
req.setQuery(assistSql);
|
||||||
|
logger.debug("calcite assistSql sql: " + assistSql);
|
||||||
|
var assistData = (List<String[]>) provider.fetchResultField(req).get("data");
|
||||||
|
result.setAssistData(assistData);
|
||||||
|
result.setDynamicAssistFields(dynamicAssistFields);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,346 @@
|
|||||||
|
package io.dataease.chart.charts.impl.table;
|
||||||
|
|
||||||
|
import io.dataease.chart.charts.impl.GroupChartHandler;
|
||||||
|
import io.dataease.constant.DeTypeConstants;
|
||||||
|
import io.dataease.engine.constant.ExtFieldConstant;
|
||||||
|
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.datasource.dto.DatasourceRequest;
|
||||||
|
import io.dataease.extensions.datasource.dto.DatasourceSchemaDTO;
|
||||||
|
import io.dataease.extensions.datasource.model.SQLMeta;
|
||||||
|
import io.dataease.extensions.datasource.provider.Provider;
|
||||||
|
import io.dataease.extensions.view.dto.*;
|
||||||
|
import io.dataease.extensions.view.util.FieldUtil;
|
||||||
|
import io.dataease.utils.BeanUtils;
|
||||||
|
import io.dataease.utils.IDUtils;
|
||||||
|
import io.dataease.utils.JsonUtil;
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import reactor.util.function.Tuple2;
|
||||||
|
import reactor.util.function.Tuples;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class TablePivotHandler extends GroupChartHandler {
|
||||||
|
@Getter
|
||||||
|
private String type = "table-pivot";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends ChartCalcDataResult> T calcChartResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, Map<String, Object> sqlMap, SQLMeta sqlMeta, Provider provider) {
|
||||||
|
T result = super.calcChartResult(view, formatResult, filterResult, sqlMap, sqlMeta, provider);
|
||||||
|
Map<String, Object> customCalc = calcCustomExpr(view, filterResult, sqlMap, sqlMeta, provider);
|
||||||
|
result.getData().put("customCalc", customCalc);
|
||||||
|
try {
|
||||||
|
var dsMap = (Map<Long, DatasourceSchemaDTO>) sqlMap.get("dsMap");
|
||||||
|
var originSql = result.getQuerySql();
|
||||||
|
var dynamicAssistFields = getDynamicThresholdFields(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, dsMap);
|
||||||
|
req.setQuery(assistSql);
|
||||||
|
logger.debug("calcite assistSql sql: " + assistSql);
|
||||||
|
var assistData = (List<String[]>) provider.fetchResultField(req).get("data");
|
||||||
|
result.setAssistData(assistData);
|
||||||
|
result.setDynamicAssistFields(dynamicAssistFields);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Object> calcCustomExpr(ChartViewDTO view, CustomFilterResult filterResult, Map<String, Object> sqlMap, SQLMeta sqlMeta, Provider provider) {
|
||||||
|
Object totalStr = JsonUtil.toJSONString(view.getCustomAttr().get("tableTotal"));
|
||||||
|
TableTotal tableTotal = JsonUtil.parseObject((String) totalStr, TableTotal.class);
|
||||||
|
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 allFields = (List<ChartViewFieldDTO>) filterResult.getContext().get("allFields");
|
||||||
|
var rowAxis = view.getXAxis();
|
||||||
|
var colAxis = view.getXAxisExt();
|
||||||
|
var dataMap = new HashMap<String, Object>();
|
||||||
|
if (CollectionUtils.isEmpty(rowAxis)) {
|
||||||
|
return dataMap;
|
||||||
|
}
|
||||||
|
// 行总计,列维度聚合加上自定义字段
|
||||||
|
var row = tableTotal.getRow();
|
||||||
|
if (row.isShowGrandTotals()) {
|
||||||
|
var yAxis = getCustomFields(view, row.getCalcTotals().getCfg());
|
||||||
|
if (!yAxis.isEmpty()) {
|
||||||
|
var tmpList = new ArrayList<>(allFields);
|
||||||
|
tmpList.addAll(yAxis);
|
||||||
|
var result = getData(sqlMeta, colAxis, yAxis, tmpList, crossDs, dsMap, view, provider, needOrder);
|
||||||
|
var querySql = result.getT1();
|
||||||
|
var data = result.getT2();
|
||||||
|
var tmp = new HashMap<String, Object>();
|
||||||
|
dataMap.put("rowTotal", tmp);
|
||||||
|
tmp.put("data", buildCustomCalcResult(data, colAxis, yAxis));
|
||||||
|
tmp.put("sql", Base64.getEncoder().encodeToString(querySql.getBytes()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 行小计,列维度聚合,自定义指标数 * (行维度的数量 - 1)
|
||||||
|
if (row.isShowSubTotals()) {
|
||||||
|
var yAxis = getCustomFields(view, row.getCalcSubTotals().getCfg());
|
||||||
|
if (!yAxis.isEmpty()) {
|
||||||
|
var tmpData = new ArrayList<Map<String, Object>>();
|
||||||
|
dataMap.put("rowSubTotal", tmpData);
|
||||||
|
for (int i = 0; i < rowAxis.size(); i++) {
|
||||||
|
if (i == rowAxis.size() - 1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
var xAxis = new ArrayList<>(colAxis);
|
||||||
|
var subRowAxis = rowAxis.subList(0, i + 1);
|
||||||
|
xAxis.addAll(subRowAxis);
|
||||||
|
if (!yAxis.isEmpty()) {
|
||||||
|
var tmpList = new ArrayList<>(allFields);
|
||||||
|
tmpList.addAll(yAxis);
|
||||||
|
var result = getData(sqlMeta, xAxis, yAxis, tmpList, crossDs, dsMap, view, provider, needOrder);
|
||||||
|
var querySql = result.getT1();
|
||||||
|
var data = result.getT2();
|
||||||
|
var tmp = new HashMap<String, Object>();
|
||||||
|
tmp.put("data", buildCustomCalcResult(data, xAxis, yAxis));
|
||||||
|
tmp.put("sql", Base64.getEncoder().encodeToString(querySql.getBytes()));
|
||||||
|
tmpData.add(tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 列总计,行维度聚合加上自定义字段
|
||||||
|
var col = tableTotal.getCol();
|
||||||
|
if (col.isShowGrandTotals() && CollectionUtils.isNotEmpty(colAxis)) {
|
||||||
|
var yAxis = getCustomFields(view, col.getCalcTotals().getCfg());
|
||||||
|
if (!yAxis.isEmpty()) {
|
||||||
|
var tmpList = new ArrayList<>(allFields);
|
||||||
|
tmpList.addAll(yAxis);
|
||||||
|
var result = getData(sqlMeta, rowAxis, yAxis, tmpList, crossDs, dsMap, view, provider, needOrder);
|
||||||
|
var querySql = result.getT1();
|
||||||
|
var data = result.getT2();
|
||||||
|
var tmp = new HashMap<String, Object>();
|
||||||
|
dataMap.put("colTotal", tmp);
|
||||||
|
tmp.put("data", buildCustomCalcResult(data, rowAxis, yAxis));
|
||||||
|
tmp.put("sql", Base64.getEncoder().encodeToString(querySql.getBytes()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 列小计,行维度聚合,自定义指标数 * (列维度的数量 - 1)
|
||||||
|
if (col.isShowSubTotals() && colAxis.size() >= 2) {
|
||||||
|
var yAxis = getCustomFields(view, col.getCalcSubTotals().getCfg());
|
||||||
|
if (!yAxis.isEmpty()) {
|
||||||
|
var tmpData = new ArrayList<Map<String, Object>>();
|
||||||
|
dataMap.put("colSubTotal", tmpData);
|
||||||
|
for (int i = 0; i < colAxis.size(); i++) {
|
||||||
|
if (i == colAxis.size() - 1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
var xAxis = new ArrayList<>(rowAxis);
|
||||||
|
var subColAxis = colAxis.subList(0, i + 1);
|
||||||
|
xAxis.addAll(subColAxis);
|
||||||
|
if (!yAxis.isEmpty()) {
|
||||||
|
var tmpList = new ArrayList<>(allFields);
|
||||||
|
tmpList.addAll(yAxis);
|
||||||
|
var result = getData(sqlMeta, xAxis, yAxis, tmpList, crossDs, dsMap, view, provider, needOrder);
|
||||||
|
var querySql = result.getT1();
|
||||||
|
var data = result.getT2();
|
||||||
|
var tmp = new HashMap<String, Object>();
|
||||||
|
tmp.put("data", buildCustomCalcResult(data, xAxis, yAxis));
|
||||||
|
tmp.put("sql", Base64.getEncoder().encodeToString(querySql.getBytes()));
|
||||||
|
tmpData.add(tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 行列交叉部分总计,无聚合,直接算,用列总计公式
|
||||||
|
if (row.isShowGrandTotals() && col.isShowGrandTotals()) {
|
||||||
|
var yAxis = getCustomFields(view, col.getCalcTotals().getCfg());
|
||||||
|
if (!yAxis.isEmpty()) {
|
||||||
|
// 清掉聚合轴
|
||||||
|
var tmpList = new ArrayList<>(allFields);
|
||||||
|
tmpList.addAll(yAxis);
|
||||||
|
var result = getData(sqlMeta, Collections.emptyList(), yAxis, tmpList, crossDs, dsMap, view, provider, needOrder);
|
||||||
|
var querySql = result.getT1();
|
||||||
|
var data = result.getT2();
|
||||||
|
var tmp = new HashMap<String, Object>();
|
||||||
|
dataMap.put("rowColTotal", tmp);
|
||||||
|
var tmpData = new HashMap<String, String>();
|
||||||
|
for (int i = 0; i < yAxis.size(); i++) {
|
||||||
|
var a = yAxis.get(i);
|
||||||
|
tmpData.put(a.getDataeaseName(), data.getFirst()[i]);
|
||||||
|
}
|
||||||
|
tmp.put("data", tmpData);
|
||||||
|
tmp.put("sql", Base64.getEncoder().encodeToString(querySql.getBytes()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 行总计里面的列小计
|
||||||
|
if (row.isShowGrandTotals() && col.isShowSubTotals() && colAxis.size() >= 2) {
|
||||||
|
var yAxis = getCustomFields(view, col.getCalcTotals().getCfg());
|
||||||
|
if (!yAxis.isEmpty()) {
|
||||||
|
var tmpData = new ArrayList<Map<String, Object>>();
|
||||||
|
dataMap.put("colSubInRowTotal", tmpData);
|
||||||
|
for (int i = 0; i < colAxis.size(); i++) {
|
||||||
|
if (i == colAxis.size() - 1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
var tmpList = new ArrayList<>(allFields);
|
||||||
|
tmpList.addAll(yAxis);
|
||||||
|
var xAxis = colAxis.subList(0, i + 1);
|
||||||
|
var result = getData(sqlMeta, xAxis, yAxis, tmpList, crossDs, dsMap, view, provider, needOrder);
|
||||||
|
var querySql = result.getT1();
|
||||||
|
var data = result.getT2();
|
||||||
|
var tmp = new HashMap<String, Object>();
|
||||||
|
tmp.put("data", buildCustomCalcResult(data, xAxis, yAxis));
|
||||||
|
tmp.put("sql", Base64.getEncoder().encodeToString(querySql.getBytes()));
|
||||||
|
tmpData.add(tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 列总计里面的行小计
|
||||||
|
if (col.isShowGrandTotals() && row.isShowGrandTotals() && rowAxis.size() >= 2) {
|
||||||
|
var yAxis = getCustomFields(view, row.getCalcTotals().getCfg());
|
||||||
|
if (!yAxis.isEmpty()) {
|
||||||
|
var tmpData = new ArrayList<Map<String, Object>>();
|
||||||
|
dataMap.put("rowSubInColTotal", tmpData);
|
||||||
|
for (int i = 0; i < rowAxis.size(); i++) {
|
||||||
|
if (i == rowAxis.size() - 1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
var tmpList = new ArrayList<>(allFields);
|
||||||
|
tmpList.addAll(yAxis);
|
||||||
|
var xAxis = rowAxis.subList(0, i + 1);
|
||||||
|
var result = getData(sqlMeta, xAxis, yAxis, tmpList, crossDs, dsMap, view, provider, needOrder);
|
||||||
|
var querySql = result.getT1();
|
||||||
|
var data = result.getT2();
|
||||||
|
var tmp = new HashMap<String, Object>();
|
||||||
|
tmp.put("data", buildCustomCalcResult(data, xAxis, yAxis));
|
||||||
|
tmp.put("sql", Base64.getEncoder().encodeToString(querySql.getBytes()));
|
||||||
|
tmpData.add(tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 行小计和列小计相交部分
|
||||||
|
if (row.isShowSubTotals() && col.isShowSubTotals() && colAxis.size() >= 2 && rowAxis.size() >= 2) {
|
||||||
|
var yAxis = getCustomFields(view, col.getCalcTotals().getCfg());
|
||||||
|
if (!yAxis.isEmpty()) {
|
||||||
|
var tmpData = new ArrayList<List<Map<String, Object>>>();
|
||||||
|
dataMap.put("rowSubInColSub", tmpData);
|
||||||
|
for (int i = 0; i < rowAxis.size(); i++) {
|
||||||
|
if (i == rowAxis.size() - 1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
var tmpList = new ArrayList<Map<String, Object>>();
|
||||||
|
tmpData.add(tmpList);
|
||||||
|
var subRow = rowAxis.subList(0, i + 1);
|
||||||
|
var xAxis = new ArrayList<>(subRow);
|
||||||
|
for (int j = 0; j < colAxis.size(); j++) {
|
||||||
|
if (j == colAxis.size() - 1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
var subCol = colAxis.subList(0, j + 1);
|
||||||
|
xAxis.addAll(subCol);
|
||||||
|
var tmpAllList = new ArrayList<>(allFields);
|
||||||
|
tmpAllList.addAll(yAxis);
|
||||||
|
var result = getData(sqlMeta, xAxis, yAxis, tmpAllList, crossDs, dsMap, view, provider, needOrder);
|
||||||
|
var querySql = result.getT1();
|
||||||
|
var data = result.getT2();
|
||||||
|
var tmp = new HashMap<String, Object>();
|
||||||
|
tmp.put("data", buildCustomCalcResult(data, xAxis, yAxis));
|
||||||
|
tmp.put("sql", Base64.getEncoder().encodeToString(querySql.getBytes()));
|
||||||
|
tmpList.add(tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dataMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Object> buildCustomCalcResult(List<String[]> data, List<ChartViewFieldDTO> dimAxis, List<ChartViewFieldDTO> quotaAxis) {
|
||||||
|
var rootResult = new HashMap<String, Object>();
|
||||||
|
if (CollectionUtils.isEmpty(dimAxis)) {
|
||||||
|
var rowData = data.getFirst();
|
||||||
|
for (int i = 0; i < rowData.length; i++) {
|
||||||
|
var qAxis = quotaAxis.get(i);
|
||||||
|
rootResult.put(qAxis.getDataeaseName(), rowData[i]);
|
||||||
|
}
|
||||||
|
return rootResult;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < data.size(); i++) {
|
||||||
|
var rowData = data.get(i);
|
||||||
|
Map<String, Object> curSubMap = rootResult;
|
||||||
|
for (int j = 0; j < dimAxis.size(); j++) {
|
||||||
|
var tmpMap = curSubMap.get(rowData[j]);
|
||||||
|
if (tmpMap == null) {
|
||||||
|
tmpMap = new HashMap<String, Object>();
|
||||||
|
curSubMap.put(rowData[j], tmpMap);
|
||||||
|
curSubMap = (Map<String, Object>) tmpMap;
|
||||||
|
} else {
|
||||||
|
curSubMap = (Map<String, Object>) tmpMap;
|
||||||
|
}
|
||||||
|
if (j == dimAxis.size() - 1) {
|
||||||
|
for (int k = 0; k < quotaAxis.size(); k++) {
|
||||||
|
var qAxis = quotaAxis.get(k);
|
||||||
|
curSubMap.put(qAxis.getDataeaseName(), rowData[j + k + 1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rootResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Tuple2<String, List<String[]>> getData(SQLMeta sqlMeta, List<ChartViewFieldDTO> xAxis, List<ChartViewFieldDTO> yAxis,
|
||||||
|
List<ChartViewFieldDTO> allFields, boolean crossDs, Map<Long, DatasourceSchemaDTO> dsMap,
|
||||||
|
ChartViewDTO view, Provider provider, boolean needOrder) {
|
||||||
|
DatasourceRequest datasourceRequest = new DatasourceRequest();
|
||||||
|
datasourceRequest.setDsList(dsMap);
|
||||||
|
Dimension2SQLObj.dimension2sqlObj(sqlMeta, xAxis, FieldUtil.transFields(allFields), crossDs, dsMap, Utils.getParams(FieldUtil.transFields(allFields)), view.getCalParams(), pluginManage);
|
||||||
|
Quota2SQLObj.quota2sqlObj(sqlMeta, yAxis, FieldUtil.transFields(allFields), crossDs, dsMap, Utils.getParams(FieldUtil.transFields(allFields)), view.getCalParams(), pluginManage);
|
||||||
|
String querySql = SQLProvider.createQuerySQL(sqlMeta, true, needOrder, view);
|
||||||
|
querySql = provider.rebuildSQL(querySql, sqlMeta, crossDs, dsMap);
|
||||||
|
datasourceRequest.setQuery(querySql);
|
||||||
|
logger.debug("calcite chart sql: " + querySql);
|
||||||
|
List<String[]> data = (List<String[]>) provider.fetchResultField(datasourceRequest).get("data");
|
||||||
|
nullToBlank(data);
|
||||||
|
return Tuples.of(querySql, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void nullToBlank(List<String[]> data) {
|
||||||
|
data.forEach(r -> {
|
||||||
|
for (int i = 0; i < r.length; i++) {
|
||||||
|
if (r[i] == null) {
|
||||||
|
r[i] = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<ChartViewFieldDTO> getCustomFields(ChartViewDTO view, List<TableCalcTotalCfg> cfgList) {
|
||||||
|
var quotaIds = view.getYAxis().stream().map(ChartViewFieldDTO::getDataeaseName).collect(Collectors.toSet());
|
||||||
|
var customFields = new ArrayList<ChartViewFieldDTO>();
|
||||||
|
for (TableCalcTotalCfg totalCfg : cfgList) {
|
||||||
|
if (!quotaIds.contains(totalCfg.getDataeaseName())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (StringUtils.equalsIgnoreCase(totalCfg.getAggregation(), "CUSTOM")) {
|
||||||
|
var field = new ChartViewFieldDTO();
|
||||||
|
field.setDeType(DeTypeConstants.DE_FLOAT);
|
||||||
|
BeanUtils.copyBean(field, totalCfg);
|
||||||
|
field.setId(IDUtils.snowID());
|
||||||
|
field.setExtField(ExtFieldConstant.EXT_CALC);
|
||||||
|
customFields.add(field);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return customFields;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
package io.dataease.chart.constant;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author gin
|
||||||
|
*/
|
||||||
|
public class ChartConstants {
|
||||||
|
public static final String YEAR_MOM = "year_mom";
|
||||||
|
public static final String MONTH_MOM = "month_mom";
|
||||||
|
public static final String YEAR_YOY = "year_yoy";
|
||||||
|
public static final String DAY_MOM = "day_mom";
|
||||||
|
public static final String MONTH_YOY = "month_yoy";
|
||||||
|
public static final String[] M_Y = {YEAR_MOM, MONTH_MOM, YEAR_YOY, DAY_MOM, MONTH_YOY};
|
||||||
|
|
||||||
|
//图表数据查询模式
|
||||||
|
public static final class VIEW_RESULT_MODE {
|
||||||
|
|
||||||
|
// 所有
|
||||||
|
public static final String ALL = "all";
|
||||||
|
|
||||||
|
// 自定义
|
||||||
|
public static final String CUSTOM = "custom";
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,640 @@
|
|||||||
|
package io.dataease.chart.dao.auto.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 组件图表表
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author fit2cloud
|
||||||
|
* @since 2024-12-12
|
||||||
|
*/
|
||||||
|
@TableName("core_chart_view")
|
||||||
|
public class CoreChartView implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ID
|
||||||
|
*/
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 标题
|
||||||
|
*/
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 场景ID chart_type为private的时候 是仪表板id
|
||||||
|
*/
|
||||||
|
private Long sceneId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数据集表ID
|
||||||
|
*/
|
||||||
|
private Long tableId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图表类型
|
||||||
|
*/
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图表渲染方式
|
||||||
|
*/
|
||||||
|
private String render;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 展示结果
|
||||||
|
*/
|
||||||
|
private Integer resultCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 展示模式
|
||||||
|
*/
|
||||||
|
private String resultMode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 横轴field
|
||||||
|
*/
|
||||||
|
private String xAxis;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* table-row
|
||||||
|
*/
|
||||||
|
private String xAxisExt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 纵轴field
|
||||||
|
*/
|
||||||
|
private String yAxis;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 副轴
|
||||||
|
*/
|
||||||
|
private String yAxisExt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 堆叠项
|
||||||
|
*/
|
||||||
|
private String extStack;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 气泡大小
|
||||||
|
*/
|
||||||
|
private String extBubble;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 动态标签
|
||||||
|
*/
|
||||||
|
private String extLabel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 动态提示
|
||||||
|
*/
|
||||||
|
private String extTooltip;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图形属性
|
||||||
|
*/
|
||||||
|
private String customAttr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 组件样式
|
||||||
|
*/
|
||||||
|
private String customStyle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 结果过滤
|
||||||
|
*/
|
||||||
|
private String customFilter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 钻取字段
|
||||||
|
*/
|
||||||
|
private String drillFields;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 高级
|
||||||
|
*/
|
||||||
|
private String senior;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建人ID
|
||||||
|
*/
|
||||||
|
private String createBy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建时间
|
||||||
|
*/
|
||||||
|
private Long createTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新时间
|
||||||
|
*/
|
||||||
|
private Long updateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 缩略图
|
||||||
|
*/
|
||||||
|
private String snapshot;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 样式优先级 panel 仪表板 view 图表
|
||||||
|
*/
|
||||||
|
private String stylePriority;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图表类型 public 公共 历史可复用的图表,private 私有 专属某个仪表板
|
||||||
|
*/
|
||||||
|
private String chartType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否插件
|
||||||
|
*/
|
||||||
|
private Boolean isPlugin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数据来源 template 模板数据 dataset 数据集数据
|
||||||
|
*/
|
||||||
|
private String dataFrom;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图表字段集合
|
||||||
|
*/
|
||||||
|
private String viewFields;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否开启刷新
|
||||||
|
*/
|
||||||
|
private Boolean refreshViewEnable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 刷新时间单位
|
||||||
|
*/
|
||||||
|
private String refreshUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 刷新时间
|
||||||
|
*/
|
||||||
|
private Integer refreshTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否开启联动
|
||||||
|
*/
|
||||||
|
private Boolean linkageActive;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否开启跳转
|
||||||
|
*/
|
||||||
|
private Boolean jumpActive;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 复制来源
|
||||||
|
*/
|
||||||
|
private Long copyFrom;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 复制ID
|
||||||
|
*/
|
||||||
|
private Long copyId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 区间条形图开启时间纬度开启聚合
|
||||||
|
*/
|
||||||
|
private Boolean aggregate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流向地图起点名称field
|
||||||
|
*/
|
||||||
|
private String flowMapStartName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流向地图终点名称field
|
||||||
|
*/
|
||||||
|
private String flowMapEndName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 颜色维度field
|
||||||
|
*/
|
||||||
|
private String extColor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图形属性_移动端
|
||||||
|
*/
|
||||||
|
private String customAttrMobile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 组件样式_移动端
|
||||||
|
*/
|
||||||
|
private String customStyleMobile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字段排序优先级
|
||||||
|
*/
|
||||||
|
private String sortPriority;
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTitle() {
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTitle(String title) {
|
||||||
|
this.title = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getSceneId() {
|
||||||
|
return sceneId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSceneId(Long sceneId) {
|
||||||
|
this.sceneId = sceneId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getTableId() {
|
||||||
|
return tableId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTableId(Long tableId) {
|
||||||
|
this.tableId = tableId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(String type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRender() {
|
||||||
|
return render;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRender(String render) {
|
||||||
|
this.render = render;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getResultCount() {
|
||||||
|
return resultCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setResultCount(Integer resultCount) {
|
||||||
|
this.resultCount = resultCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getResultMode() {
|
||||||
|
return resultMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setResultMode(String resultMode) {
|
||||||
|
this.resultMode = resultMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getxAxis() {
|
||||||
|
return xAxis;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setxAxis(String xAxis) {
|
||||||
|
this.xAxis = xAxis;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getxAxisExt() {
|
||||||
|
return xAxisExt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setxAxisExt(String xAxisExt) {
|
||||||
|
this.xAxisExt = xAxisExt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getyAxis() {
|
||||||
|
return yAxis;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setyAxis(String yAxis) {
|
||||||
|
this.yAxis = yAxis;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getyAxisExt() {
|
||||||
|
return yAxisExt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setyAxisExt(String yAxisExt) {
|
||||||
|
this.yAxisExt = yAxisExt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getExtStack() {
|
||||||
|
return extStack;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExtStack(String extStack) {
|
||||||
|
this.extStack = extStack;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getExtBubble() {
|
||||||
|
return extBubble;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExtBubble(String extBubble) {
|
||||||
|
this.extBubble = extBubble;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getExtLabel() {
|
||||||
|
return extLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExtLabel(String extLabel) {
|
||||||
|
this.extLabel = extLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getExtTooltip() {
|
||||||
|
return extTooltip;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExtTooltip(String extTooltip) {
|
||||||
|
this.extTooltip = extTooltip;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCustomAttr() {
|
||||||
|
return customAttr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCustomAttr(String customAttr) {
|
||||||
|
this.customAttr = customAttr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCustomStyle() {
|
||||||
|
return customStyle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCustomStyle(String customStyle) {
|
||||||
|
this.customStyle = customStyle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCustomFilter() {
|
||||||
|
return customFilter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCustomFilter(String customFilter) {
|
||||||
|
this.customFilter = customFilter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDrillFields() {
|
||||||
|
return drillFields;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDrillFields(String drillFields) {
|
||||||
|
this.drillFields = drillFields;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSenior() {
|
||||||
|
return senior;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSenior(String senior) {
|
||||||
|
this.senior = senior;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCreateBy() {
|
||||||
|
return createBy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreateBy(String createBy) {
|
||||||
|
this.createBy = createBy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getCreateTime() {
|
||||||
|
return createTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreateTime(Long createTime) {
|
||||||
|
this.createTime = createTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getUpdateTime() {
|
||||||
|
return updateTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUpdateTime(Long updateTime) {
|
||||||
|
this.updateTime = updateTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSnapshot() {
|
||||||
|
return snapshot;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSnapshot(String snapshot) {
|
||||||
|
this.snapshot = snapshot;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStylePriority() {
|
||||||
|
return stylePriority;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStylePriority(String stylePriority) {
|
||||||
|
this.stylePriority = stylePriority;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getChartType() {
|
||||||
|
return chartType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setChartType(String chartType) {
|
||||||
|
this.chartType = chartType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getIsPlugin() {
|
||||||
|
return isPlugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIsPlugin(Boolean isPlugin) {
|
||||||
|
this.isPlugin = isPlugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDataFrom() {
|
||||||
|
return dataFrom;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDataFrom(String dataFrom) {
|
||||||
|
this.dataFrom = dataFrom;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getViewFields() {
|
||||||
|
return viewFields;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setViewFields(String viewFields) {
|
||||||
|
this.viewFields = viewFields;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getRefreshViewEnable() {
|
||||||
|
return refreshViewEnable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRefreshViewEnable(Boolean refreshViewEnable) {
|
||||||
|
this.refreshViewEnable = refreshViewEnable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRefreshUnit() {
|
||||||
|
return refreshUnit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRefreshUnit(String refreshUnit) {
|
||||||
|
this.refreshUnit = refreshUnit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getRefreshTime() {
|
||||||
|
return refreshTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRefreshTime(Integer refreshTime) {
|
||||||
|
this.refreshTime = refreshTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getLinkageActive() {
|
||||||
|
return linkageActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLinkageActive(Boolean linkageActive) {
|
||||||
|
this.linkageActive = linkageActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getJumpActive() {
|
||||||
|
return jumpActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setJumpActive(Boolean jumpActive) {
|
||||||
|
this.jumpActive = jumpActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getCopyFrom() {
|
||||||
|
return copyFrom;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCopyFrom(Long copyFrom) {
|
||||||
|
this.copyFrom = copyFrom;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getCopyId() {
|
||||||
|
return copyId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCopyId(Long copyId) {
|
||||||
|
this.copyId = copyId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getAggregate() {
|
||||||
|
return aggregate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAggregate(Boolean aggregate) {
|
||||||
|
this.aggregate = aggregate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFlowMapStartName() {
|
||||||
|
return flowMapStartName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFlowMapStartName(String flowMapStartName) {
|
||||||
|
this.flowMapStartName = flowMapStartName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFlowMapEndName() {
|
||||||
|
return flowMapEndName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFlowMapEndName(String flowMapEndName) {
|
||||||
|
this.flowMapEndName = flowMapEndName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getExtColor() {
|
||||||
|
return extColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExtColor(String extColor) {
|
||||||
|
this.extColor = extColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCustomAttrMobile() {
|
||||||
|
return customAttrMobile;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCustomAttrMobile(String customAttrMobile) {
|
||||||
|
this.customAttrMobile = customAttrMobile;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCustomStyleMobile() {
|
||||||
|
return customStyleMobile;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCustomStyleMobile(String customStyleMobile) {
|
||||||
|
this.customStyleMobile = customStyleMobile;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSortPriority() {
|
||||||
|
return sortPriority;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSortPriority(String sortPriority) {
|
||||||
|
this.sortPriority = sortPriority;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "CoreChartView{" +
|
||||||
|
"id = " + id +
|
||||||
|
", title = " + title +
|
||||||
|
", sceneId = " + sceneId +
|
||||||
|
", tableId = " + tableId +
|
||||||
|
", type = " + type +
|
||||||
|
", render = " + render +
|
||||||
|
", resultCount = " + resultCount +
|
||||||
|
", resultMode = " + resultMode +
|
||||||
|
", xAxis = " + xAxis +
|
||||||
|
", xAxisExt = " + xAxisExt +
|
||||||
|
", yAxis = " + yAxis +
|
||||||
|
", yAxisExt = " + yAxisExt +
|
||||||
|
", extStack = " + extStack +
|
||||||
|
", extBubble = " + extBubble +
|
||||||
|
", extLabel = " + extLabel +
|
||||||
|
", extTooltip = " + extTooltip +
|
||||||
|
", customAttr = " + customAttr +
|
||||||
|
", customStyle = " + customStyle +
|
||||||
|
", customFilter = " + customFilter +
|
||||||
|
", drillFields = " + drillFields +
|
||||||
|
", senior = " + senior +
|
||||||
|
", createBy = " + createBy +
|
||||||
|
", createTime = " + createTime +
|
||||||
|
", updateTime = " + updateTime +
|
||||||
|
", snapshot = " + snapshot +
|
||||||
|
", stylePriority = " + stylePriority +
|
||||||
|
", chartType = " + chartType +
|
||||||
|
", isPlugin = " + isPlugin +
|
||||||
|
", dataFrom = " + dataFrom +
|
||||||
|
", viewFields = " + viewFields +
|
||||||
|
", refreshViewEnable = " + refreshViewEnable +
|
||||||
|
", refreshUnit = " + refreshUnit +
|
||||||
|
", refreshTime = " + refreshTime +
|
||||||
|
", linkageActive = " + linkageActive +
|
||||||
|
", jumpActive = " + jumpActive +
|
||||||
|
", copyFrom = " + copyFrom +
|
||||||
|
", copyId = " + copyId +
|
||||||
|
", aggregate = " + aggregate +
|
||||||
|
", flowMapStartName = " + flowMapStartName +
|
||||||
|
", flowMapEndName = " + flowMapEndName +
|
||||||
|
", extColor = " + extColor +
|
||||||
|
", customAttrMobile = " + customAttrMobile +
|
||||||
|
", customStyleMobile = " + customStyleMobile +
|
||||||
|
", sortPriority = " + sortPriority +
|
||||||
|
"}";
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package io.dataease.chart.dao.auto.mapper;
|
||||||
|
|
||||||
|
import io.dataease.chart.dao.auto.entity.CoreChartView;
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 组件图表表 Mapper 接口
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author fit2cloud
|
||||||
|
* @since 2024-12-12
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface CoreChartViewMapper extends BaseMapper<CoreChartView> {
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
package io.dataease.chart.dao.ext.entity;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class ChartBasePO implements Serializable {
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 183064537525500481L;
|
||||||
|
|
||||||
|
private Long chartId;
|
||||||
|
|
||||||
|
private String chartType;
|
||||||
|
|
||||||
|
private String chartName;
|
||||||
|
|
||||||
|
private Long resourceId;
|
||||||
|
|
||||||
|
private String resourceType;
|
||||||
|
|
||||||
|
private String resourceName;
|
||||||
|
|
||||||
|
private Long tableId;
|
||||||
|
|
||||||
|
private String xAxis;
|
||||||
|
|
||||||
|
|
||||||
|
private String xAxisExt;
|
||||||
|
|
||||||
|
|
||||||
|
private String yAxis;
|
||||||
|
|
||||||
|
|
||||||
|
private String yAxisExt;
|
||||||
|
|
||||||
|
|
||||||
|
private String extStack;
|
||||||
|
|
||||||
|
|
||||||
|
private String extBubble;
|
||||||
|
|
||||||
|
private String flowMapStartName;
|
||||||
|
|
||||||
|
private String flowMapEndName;
|
||||||
|
|
||||||
|
private String extColor;
|
||||||
|
|
||||||
|
private String extLabel;
|
||||||
|
|
||||||
|
private String extTooltip;
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
package io.dataease.chart.dao.ext.mapper;
|
||||||
|
|
||||||
|
import io.dataease.api.chart.vo.ViewSelectorVO;
|
||||||
|
import io.dataease.chart.dao.ext.entity.ChartBasePO;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
import org.apache.ibatis.annotations.Select;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface ExtChartViewMapper {
|
||||||
|
|
||||||
|
@Select("""
|
||||||
|
select id, scene_id as pid, title, type from core_chart_view where type != 'VQuery' and scene_id = #{resourceId}
|
||||||
|
""")
|
||||||
|
List<ViewSelectorVO> queryViewOption(@Param("resourceId") Long resourceId);
|
||||||
|
|
||||||
|
@Select("""
|
||||||
|
select
|
||||||
|
ccv.id as chart_id,
|
||||||
|
ccv.title as chart_name,
|
||||||
|
ccv.type as chart_type,
|
||||||
|
ccv.table_id,
|
||||||
|
dvi.id as resource_id,
|
||||||
|
dvi.name as resource_name,
|
||||||
|
dvi.type as resource_type,
|
||||||
|
ccv.x_axis,
|
||||||
|
ccv.x_axis_ext,
|
||||||
|
ccv.y_axis,
|
||||||
|
ccv.y_axis_ext,
|
||||||
|
ccv.ext_stack,
|
||||||
|
ccv.ext_bubble,
|
||||||
|
ccv.ext_label,
|
||||||
|
ccv.ext_tooltip,
|
||||||
|
ccv.flow_map_start_name,
|
||||||
|
ccv.flow_map_end_name,
|
||||||
|
ccv.ext_color
|
||||||
|
from core_chart_view ccv
|
||||||
|
left join data_visualization_info dvi on dvi.id = ccv.scene_id
|
||||||
|
where ccv.id = #{id}
|
||||||
|
""")
|
||||||
|
ChartBasePO queryChart(@Param("id") Long id);
|
||||||
|
}
|
@ -0,0 +1,830 @@
|
|||||||
|
package io.dataease.chart.manage;
|
||||||
|
|
||||||
|
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.ChartHandlerManager;
|
||||||
|
import io.dataease.chart.constant.ChartConstants;
|
||||||
|
import io.dataease.constant.AuthEnum;
|
||||||
|
import io.dataease.dataset.manage.DatasetGroupManage;
|
||||||
|
import io.dataease.dataset.manage.DatasetSQLManage;
|
||||||
|
import io.dataease.dataset.manage.DatasetTableFieldManage;
|
||||||
|
import io.dataease.dataset.manage.PermissionManage;
|
||||||
|
import io.dataease.engine.sql.SQLProvider;
|
||||||
|
import io.dataease.engine.trans.*;
|
||||||
|
import io.dataease.engine.utils.SQLUtils;
|
||||||
|
import io.dataease.engine.utils.Utils;
|
||||||
|
import io.dataease.exception.DEException;
|
||||||
|
import io.dataease.extensions.datasource.api.PluginManageApi;
|
||||||
|
import io.dataease.extensions.datasource.dto.DatasetTableFieldDTO;
|
||||||
|
import io.dataease.extensions.datasource.dto.DatasourceRequest;
|
||||||
|
import io.dataease.extensions.datasource.dto.DatasourceSchemaDTO;
|
||||||
|
import io.dataease.extensions.datasource.factory.ProviderFactory;
|
||||||
|
import io.dataease.extensions.datasource.model.SQLMeta;
|
||||||
|
import io.dataease.extensions.datasource.provider.Provider;
|
||||||
|
import io.dataease.extensions.view.dto.*;
|
||||||
|
import io.dataease.extensions.view.factory.PluginsChartFactory;
|
||||||
|
import io.dataease.extensions.view.filter.FilterTreeObj;
|
||||||
|
import io.dataease.extensions.view.plugin.AbstractChartPlugin;
|
||||||
|
import io.dataease.extensions.view.util.FieldUtil;
|
||||||
|
import io.dataease.i18n.Translator;
|
||||||
|
import io.dataease.result.ResultCode;
|
||||||
|
import io.dataease.system.manage.CorePermissionManage;
|
||||||
|
import io.dataease.utils.AuthUtils;
|
||||||
|
import io.dataease.utils.BeanUtils;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.apache.commons.collections4.MapUtils;
|
||||||
|
import org.apache.commons.lang3.BooleanUtils;
|
||||||
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author Junjun
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class ChartDataManage {
|
||||||
|
@Resource
|
||||||
|
private DatasetTableFieldManage datasetTableFieldManage;
|
||||||
|
@Resource
|
||||||
|
private DatasetGroupManage datasetGroupManage;
|
||||||
|
@Resource
|
||||||
|
private DatasetSQLManage datasetSQLManage;
|
||||||
|
@Resource
|
||||||
|
private ChartViewManege chartViewManege;
|
||||||
|
@Resource
|
||||||
|
private PermissionManage permissionManage;
|
||||||
|
@Resource
|
||||||
|
private ChartFilterTreeService chartFilterTreeService;
|
||||||
|
@Resource
|
||||||
|
private ChartHandlerManager chartHandlerManager;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private CorePermissionManage corePermissionManage;
|
||||||
|
@Autowired(required = false)
|
||||||
|
private PluginManageApi pluginManage;
|
||||||
|
|
||||||
|
public static final String START_END_SEPARATOR = "_START_END_SPLIT";
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(ChartDataManage.class);
|
||||||
|
|
||||||
|
public ChartViewDTO calcData(ChartViewDTO view) throws Exception {
|
||||||
|
ChartExtRequest chartExtRequest = view.getChartExtRequest();
|
||||||
|
if (chartExtRequest == null) {
|
||||||
|
chartExtRequest = new ChartExtRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ObjectUtils.isEmpty(view)) {
|
||||||
|
DEException.throwException(ResultCode.DATA_IS_WRONG.code(), Translator.get("i18n_chart_delete"));
|
||||||
|
}
|
||||||
|
if (ObjectUtils.isNotEmpty(AuthUtils.getUser())) {
|
||||||
|
chartExtRequest.setUser(AuthUtils.getUser().getUserId());
|
||||||
|
}
|
||||||
|
if (view.getChartExtRequest() == null) {
|
||||||
|
view.setChartExtRequest(chartExtRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
//excel导出,如果是从仪表板获取图表数据,则仪表板的查询模式,查询结果的数量,覆盖图表对应的属性
|
||||||
|
if (view.getIsExcelExport()) {
|
||||||
|
view.setResultMode(ChartConstants.VIEW_RESULT_MODE.CUSTOM);
|
||||||
|
} else if (ChartConstants.VIEW_RESULT_MODE.CUSTOM.equals(chartExtRequest.getResultMode())) {
|
||||||
|
view.setResultMode(chartExtRequest.getResultMode());
|
||||||
|
view.setResultCount(chartExtRequest.getResultCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
AbstractChartPlugin chartHandler;
|
||||||
|
if (BooleanUtils.isTrue(view.getIsPlugin())) {
|
||||||
|
chartHandler = PluginsChartFactory.getInstance(view.getRender(), view.getType());
|
||||||
|
} else {
|
||||||
|
chartHandler = chartHandlerManager.getChartHandler(view.getRender(), view.getType());
|
||||||
|
}
|
||||||
|
if (chartHandler == null) {
|
||||||
|
DEException.throwException(ResultCode.DATA_IS_WRONG.code(), Translator.get("i18n_chart_not_handler") + ": " + view.getRender() + "," + view.getType());
|
||||||
|
}
|
||||||
|
|
||||||
|
var dillAxis = new ArrayList<ChartViewFieldDTO>();
|
||||||
|
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_dataset_permission"));
|
||||||
|
}
|
||||||
|
|
||||||
|
List<ChartViewFieldDTO> allFields = getAllChartFields(view);
|
||||||
|
// 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("*");
|
||||||
|
AxisFormatResult formatResult = chartHandler.formatAxis(view);
|
||||||
|
formatResult.getContext().put("desensitizationList", desensitizationList);
|
||||||
|
var xAxis = formatResult.getAxisMap().get(ChartAxis.xAxis);
|
||||||
|
var yAxis = formatResult.getAxisMap().get(ChartAxis.yAxis);
|
||||||
|
formatResult.getContext().put("allFields", allFields);
|
||||||
|
var axisMap = formatResult.getAxisMap();
|
||||||
|
axisMap.forEach((axis, fields) -> {
|
||||||
|
fields.removeIf(fieldDTO -> !dataeaseNames.contains(fieldDTO.getDataeaseName()));
|
||||||
|
});
|
||||||
|
|
||||||
|
// 过滤来自仪表板的条件
|
||||||
|
List<ChartExtFilterDTO> extFilterList = new ArrayList<>();
|
||||||
|
//组件过滤条件
|
||||||
|
List<SqlVariableDetails> sqlVariables = datasetGroupManage.getSqlParams(Collections.singletonList(view.getTableId()));
|
||||||
|
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;
|
||||||
|
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.getDatasetGroupId(), 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());
|
||||||
|
}
|
||||||
|
|
||||||
|
// web参数条件
|
||||||
|
if (ObjectUtils.isNotEmpty(chartExtRequest.getWebParamsFilters())) {
|
||||||
|
filters.addAll(chartExtRequest.getWebParamsFilters());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//联动过滤条件和外部参数过滤条件全部加上
|
||||||
|
if (ObjectUtils.isNotEmpty(filters)) {
|
||||||
|
for (ChartExtFilterDTO request : filters) {
|
||||||
|
// 包含 DE 的为数据集参数
|
||||||
|
if (request.getFieldId().contains("DE")) {
|
||||||
|
// 组装sql 参数原始数据
|
||||||
|
if (CollectionUtils.isNotEmpty(sqlVariables)) {
|
||||||
|
for (SqlVariableDetails sourceVariables : sqlVariables) {
|
||||||
|
if (sourceVariables.getId().equals(request.getFieldId())) {
|
||||||
|
if (CollectionUtils.isEmpty(request.getParameters())) {
|
||||||
|
request.setParameters(new ArrayList<>());
|
||||||
|
}
|
||||||
|
request.getParameters().add(sourceVariables);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
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");
|
||||||
|
drillFilter.setOriginValue(Collections.singletonList(dim.getValue()));
|
||||||
|
// 把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);
|
||||||
|
dillAxis.add(viewField);
|
||||||
|
fields.add(dim.getId());
|
||||||
|
}
|
||||||
|
if (i == drillRequestList.size() - 1) {
|
||||||
|
ChartViewFieldDTO nextDrillField = drill.get(i + 1);
|
||||||
|
if (!fields.contains(nextDrillField.getId())) {
|
||||||
|
nextDrillField.setSource(FieldSource.DRILL);
|
||||||
|
xAxis.add(nextDrillField);
|
||||||
|
dillAxis.add(nextDrillField);
|
||||||
|
fields.add(nextDrillField.getId());
|
||||||
|
} else {
|
||||||
|
Optional<ChartViewFieldDTO> axis = xAxis.stream().filter(x -> Objects.equals(x.getId(), nextDrillField.getId())).findFirst();
|
||||||
|
axis.ifPresent(field -> {
|
||||||
|
field.setSort(nextDrillField.getSort());
|
||||||
|
field.setCustomSort(nextDrillField.getCustomSort());
|
||||||
|
});
|
||||||
|
dillAxis.add(nextDrillField);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
formatResult.getContext().put("dillAxis", dillAxis);
|
||||||
|
|
||||||
|
//转义特殊字符
|
||||||
|
extFilterList = extFilterList.stream().peek(ele -> {
|
||||||
|
if (ObjectUtils.isNotEmpty(ele.getValue())) {
|
||||||
|
List<String> collect = ele.getValue().stream().map(SQLUtils::transKeyword).collect(Collectors.toList());
|
||||||
|
if (CollectionUtils.isEmpty(ele.getOriginValue())) {
|
||||||
|
ele.setOriginValue(ele.getValue());
|
||||||
|
}
|
||||||
|
ele.setValue(collect);
|
||||||
|
}
|
||||||
|
}).collect(Collectors.toList());
|
||||||
|
// 视图自定义过滤逻辑
|
||||||
|
CustomFilterResult filterResult = chartHandler.customFilter(view, extFilterList, formatResult);
|
||||||
|
|
||||||
|
if (ObjectUtils.isEmpty(xAxis) && ObjectUtils.isEmpty(yAxis)) {
|
||||||
|
return emptyChartViewDTO(view);
|
||||||
|
}
|
||||||
|
// 字段过滤器
|
||||||
|
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");
|
||||||
|
boolean crossDs = Utils.isCrossDs(dsMap);
|
||||||
|
if (!crossDs) {
|
||||||
|
sql = Utils.replaceSchemaAlias(sql, dsMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
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"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Provider provider;
|
||||||
|
if (crossDs) {
|
||||||
|
provider = ProviderFactory.getDefaultProvider();
|
||||||
|
} else {
|
||||||
|
provider = ProviderFactory.getProvider(dsMap.entrySet().iterator().next().getValue().getType());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ObjectUtils.isEmpty(view.getCalParams())) {
|
||||||
|
view.setCalParams(Utils.getParams(transFields(allFields)));
|
||||||
|
}
|
||||||
|
|
||||||
|
SQLMeta sqlMeta = new SQLMeta();
|
||||||
|
Table2SQLObj.table2sqlobj(sqlMeta, null, "(" + sql + ")", crossDs);
|
||||||
|
CustomWhere2Str.customWhere2sqlObj(sqlMeta, fieldCustomFilter, transFields(allFields), crossDs, dsMap, Utils.getParams(transFields(allFields)), view.getCalParams(), pluginManage);
|
||||||
|
ExtWhere2Str.extWhere2sqlOjb(sqlMeta, extFilterList, transFields(allFields), crossDs, dsMap, Utils.getParams(transFields(allFields)), view.getCalParams(), pluginManage);
|
||||||
|
WhereTree2Str.transFilterTrees(sqlMeta, rowPermissionsTree, transFields(allFields), crossDs, dsMap, Utils.getParams(transFields(allFields)), view.getCalParams(), pluginManage);
|
||||||
|
// TODO 數據源插件化之後放到插件裡面組裝SQL
|
||||||
|
if (BooleanUtils.isTrue(view.getIsPlugin())) {
|
||||||
|
List<String> dsList = new ArrayList<>();
|
||||||
|
for (Map.Entry<Long, DatasourceSchemaDTO> next : dsMap.entrySet()) {
|
||||||
|
dsList.add(next.getValue().getType());
|
||||||
|
}
|
||||||
|
boolean needOrder = Utils.isNeedOrder(dsList);
|
||||||
|
Dimension2SQLObj.dimension2sqlObj(sqlMeta, xAxis, FieldUtil.transFields(allFields), crossDs, dsMap, Utils.getParams(FieldUtil.transFields(allFields)), view.getCalParams(), pluginManage);
|
||||||
|
Quota2SQLObj.quota2sqlObj(sqlMeta, yAxis, FieldUtil.transFields(allFields), crossDs, dsMap, Utils.getParams(FieldUtil.transFields(allFields)), view.getCalParams(), pluginManage);
|
||||||
|
String querySql = SQLProvider.createQuerySQL(sqlMeta, true, needOrder, view);
|
||||||
|
querySql = provider.rebuildSQL(querySql, sqlMeta, crossDs, dsMap);
|
||||||
|
filterResult.getContext().put("querySql", querySql);
|
||||||
|
}
|
||||||
|
|
||||||
|
ChartCalcDataResult calcResult = chartHandler.calcChartResult(view, formatResult, filterResult, sqlMap, sqlMeta, provider);
|
||||||
|
return chartHandler.buildChart(view, calcResult, formatResult, filterResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<ChartViewFieldDTO> getSizeField(ChartViewDTO view) throws Exception {
|
||||||
|
List<ChartViewFieldDTO> list = new ArrayList<>();
|
||||||
|
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) {
|
||||||
|
list.add(gaugeMinViewField);
|
||||||
|
}
|
||||||
|
ChartViewFieldDTO gaugeMaxViewField = getDynamicField(size, "gaugeMaxType", "gaugeMaxField");
|
||||||
|
if (gaugeMaxViewField != null) {
|
||||||
|
list.add(gaugeMaxViewField);
|
||||||
|
}
|
||||||
|
ChartViewFieldDTO liquidMaxViewField = getDynamicField(size, "liquidMaxType", "liquidMaxField");
|
||||||
|
if (liquidMaxViewField != null) {
|
||||||
|
list.add(liquidMaxViewField);
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ChartViewFieldDTO getDynamicField(Map<String, Object> sizeObj, String type, String field) {
|
||||||
|
String maxType = (String) sizeObj.get(type);
|
||||||
|
if (StringUtils.equalsIgnoreCase("dynamic", maxType)) {
|
||||||
|
Map<String, Object> maxField = (Map<String, Object>) sizeObj.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ChartViewDTO emptyChartViewDTO(ChartViewDTO view) {
|
||||||
|
ChartViewDTO dto = new ChartViewDTO();
|
||||||
|
BeanUtils.copyBean(dto, view);
|
||||||
|
return dto;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<DatasetTableFieldDTO> transFields(List<? extends ChartViewFieldBaseDTO> list) {
|
||||||
|
return list.stream().map(ele -> {
|
||||||
|
DatasetTableFieldDTO dto = new DatasetTableFieldDTO();
|
||||||
|
BeanUtils.copyBean(dto, ele);
|
||||||
|
return dto;
|
||||||
|
}).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 对结果排序
|
||||||
|
public 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 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getFieldData(ChartViewDTO view, Long fieldId, String fieldType) throws Exception {
|
||||||
|
ChartExtRequest requestList = view.getChartExtRequest();
|
||||||
|
List<String[]> sqlData = sqlData(view, requestList, fieldId);
|
||||||
|
List<ChartViewFieldDTO> fieldList = new ArrayList<>();
|
||||||
|
switch (fieldType) {
|
||||||
|
case "xAxis" -> fieldList = view.getXAxis();
|
||||||
|
case "xAxisExt" -> fieldList = view.getXAxisExt();
|
||||||
|
case "extStack" -> fieldList = view.getExtStack();
|
||||||
|
}
|
||||||
|
DatasetTableFieldDTO field = datasetTableFieldManage.selectById(fieldId);
|
||||||
|
|
||||||
|
List<String> res = new ArrayList<>();
|
||||||
|
if (ObjectUtils.isNotEmpty(field) && fieldList.size() > 0) {
|
||||||
|
// 找到对应维度
|
||||||
|
ChartViewFieldDTO chartViewFieldDTO = null;
|
||||||
|
int index = 0;
|
||||||
|
int getIndex = 0;
|
||||||
|
for (int i = 0; i < fieldList.size(); i++) {
|
||||||
|
ChartViewFieldDTO item = fieldList.get(i);
|
||||||
|
if (StringUtils.equalsIgnoreCase(item.getSort(), "custom_sort")) {// 此处与已有的自定义字段对比
|
||||||
|
chartViewFieldDTO = item;
|
||||||
|
index = i;
|
||||||
|
}
|
||||||
|
if (Objects.equals(item.getId(), field.getId())) {// 获得当前自定义的字段
|
||||||
|
getIndex = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (StringUtils.equalsIgnoreCase(fieldType, "xAxisExt")) {
|
||||||
|
List<ChartViewFieldDTO> xAxis = view.getXAxis();
|
||||||
|
index += xAxis.size();
|
||||||
|
getIndex += xAxis.size();
|
||||||
|
}
|
||||||
|
if (StringUtils.equalsIgnoreCase(fieldType, "extStack")) {
|
||||||
|
int xAxisSize = CollectionUtils.size(view.getXAxis());
|
||||||
|
int extSize = CollectionUtils.size(view.getXAxisExt());
|
||||||
|
index += xAxisSize + extSize;
|
||||||
|
getIndex += xAxisSize + extSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String[]> sortResult = resultCustomSort(fieldList, sqlData);
|
||||||
|
if (ObjectUtils.isNotEmpty(chartViewFieldDTO) && (getIndex >= index)) {
|
||||||
|
// 获取自定义值与data对应列的结果
|
||||||
|
List<String[]> strings = customSort(Optional.ofNullable(chartViewFieldDTO.getCustomSort()).orElse(new ArrayList<>()), sortResult, index);
|
||||||
|
for (int i = 0; i < strings.size(); i++) {
|
||||||
|
res.add(strings.get(i)[getIndex]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 返回请求结果
|
||||||
|
for (int i = 0; i < sortResult.size(); i++) {
|
||||||
|
res.add(sortResult.get(i)[getIndex]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res.stream().distinct().collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String[]> sqlData(ChartViewDTO view, ChartExtRequest requestList, Long fieldId) throws Exception {
|
||||||
|
if (ObjectUtils.isEmpty(view)) {
|
||||||
|
DEException.throwException(Translator.get("i18n_chart_delete"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// get all fields
|
||||||
|
List<ChartViewFieldDTO> allFields = getAllChartFields(view);
|
||||||
|
|
||||||
|
// 针对分组切换堆叠时会遇到的问题
|
||||||
|
if (StringUtils.equalsIgnoreCase(view.getType(), "bar-stack") || StringUtils.equalsIgnoreCase(view.getType(), "chart-mix-stack")) {
|
||||||
|
view.setXAxisExt(new ArrayList<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
List<ChartViewFieldDTO> xAxisBase = new ArrayList<>(view.getXAxis());
|
||||||
|
List<ChartViewFieldDTO> xAxis = new ArrayList<>(view.getXAxis());
|
||||||
|
List<ChartViewFieldDTO> xAxisExt = new ArrayList<>(view.getXAxisExt());
|
||||||
|
if (StringUtils.equalsIgnoreCase(view.getType(), "table-pivot")
|
||||||
|
|| StringUtils.containsIgnoreCase(view.getType(), "group")
|
||||||
|
|| ("antv".equalsIgnoreCase(view.getRender()) && "line".equalsIgnoreCase(view.getType()))
|
||||||
|
|| StringUtils.equalsIgnoreCase(view.getType(), "flow-map")
|
||||||
|
|| StringUtils.equalsIgnoreCase(view.getType(), "t-heatmap")
|
||||||
|
|| StringUtils.equalsIgnoreCase(view.getType(), "sankey")
|
||||||
|
) {
|
||||||
|
xAxis.addAll(xAxisExt);
|
||||||
|
}
|
||||||
|
List<ChartViewFieldDTO> yAxis = new ArrayList<>(view.getYAxis());
|
||||||
|
if (StringUtils.containsIgnoreCase(view.getType(), "chart-mix")) {
|
||||||
|
List<ChartViewFieldDTO> yAxisExt = new ArrayList<>(view.getYAxisExt());
|
||||||
|
yAxis.addAll(yAxisExt);
|
||||||
|
}
|
||||||
|
if (StringUtils.equalsIgnoreCase(view.getRender(), "antv") && StringUtils.equalsAnyIgnoreCase(view.getType(), "gauge", "liquid")) {
|
||||||
|
List<ChartViewFieldDTO> sizeField = getSizeField(view);
|
||||||
|
yAxis.addAll(sizeField);
|
||||||
|
}
|
||||||
|
List<ChartViewFieldDTO> extStack = new ArrayList<>(view.getExtStack());
|
||||||
|
List<ChartViewFieldDTO> extBubble = new ArrayList<>(view.getExtBubble());
|
||||||
|
FilterTreeObj fieldCustomFilter = view.getCustomFilter();
|
||||||
|
List<ChartViewFieldDTO> drill = new ArrayList<>(view.getDrillFields());
|
||||||
|
|
||||||
|
// 获取数据集,需校验权限
|
||||||
|
DatasetGroupInfoDTO table = datasetGroupManage.getDatasetGroupInfoDTO(view.getTableId(), null);
|
||||||
|
Map<String, ColumnPermissionItem> desensitizationList = new HashMap<>();
|
||||||
|
List<DataSetRowPermissionsTreeDTO> rowPermissionsTree = permissionManage.getRowPermissionsTree(table.getId(), view.getChartExtRequest().getUser());
|
||||||
|
|
||||||
|
chartFilterTreeService.searchFieldAndSet(fieldCustomFilter);
|
||||||
|
|
||||||
|
if (ObjectUtils.isEmpty(xAxis) && ObjectUtils.isEmpty(yAxis)) {
|
||||||
|
return new ArrayList<String[]>();
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (view.getType()) {
|
||||||
|
case "label":
|
||||||
|
yAxis = new ArrayList<>();
|
||||||
|
if (ObjectUtils.isEmpty(xAxis)) {
|
||||||
|
return new ArrayList<String[]>();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "indicator":
|
||||||
|
case "gauge":
|
||||||
|
case "liquid":
|
||||||
|
xAxis = new ArrayList<>();
|
||||||
|
if (ObjectUtils.isEmpty(yAxis)) {
|
||||||
|
return new ArrayList<String[]>();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "table-info":
|
||||||
|
yAxis = new ArrayList<>();
|
||||||
|
if (ObjectUtils.isEmpty(xAxis)) {
|
||||||
|
return new ArrayList<String[]>();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "table-normal":
|
||||||
|
break;
|
||||||
|
case "bar-group":
|
||||||
|
case "bar-group-stack":
|
||||||
|
case "flow-map":
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取dsMap,union sql
|
||||||
|
Map<String, Object> sqlMap = datasetSQLManage.getUnionSQLForEdit(table, null);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调用数据源的calcite获得data
|
||||||
|
DatasourceRequest datasourceRequest = new DatasourceRequest();
|
||||||
|
datasourceRequest.setDsList(dsMap);
|
||||||
|
|
||||||
|
Provider provider;
|
||||||
|
if (crossDs) {
|
||||||
|
provider = ProviderFactory.getDefaultProvider();
|
||||||
|
} else {
|
||||||
|
provider = ProviderFactory.getProvider(dsMap.entrySet().iterator().next().getValue().getType());
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String[]> data = new ArrayList<>();
|
||||||
|
|
||||||
|
String querySql = null;
|
||||||
|
//如果不是插件图表 走原生逻辑
|
||||||
|
if (table.getMode() == 0) {// 直连
|
||||||
|
if (ObjectUtils.isEmpty(dsMap)) {
|
||||||
|
DEException.throwException(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(Translator.get("i18n_invalid_ds"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SQLMeta sqlMeta = new SQLMeta();
|
||||||
|
Table2SQLObj.table2sqlobj(sqlMeta, null, "(" + sql + ")", crossDs);
|
||||||
|
WhereTree2Str.transFilterTrees(sqlMeta, rowPermissionsTree, transFields(allFields), crossDs, dsMap, Utils.getParams(transFields(allFields)), view.getCalParams(), pluginManage);
|
||||||
|
|
||||||
|
if (StringUtils.equalsAnyIgnoreCase(view.getType(), "indicator", "gauge", "liquid")) {
|
||||||
|
Quota2SQLObj.quota2sqlObj(sqlMeta, yAxis, transFields(allFields), crossDs, dsMap, Utils.getParams(transFields(allFields)), view.getCalParams(), pluginManage);
|
||||||
|
querySql = SQLProvider.createQuerySQL(sqlMeta, true, needOrder, view);
|
||||||
|
} else if (StringUtils.containsIgnoreCase(view.getType(), "stack")) {
|
||||||
|
List<ChartViewFieldDTO> xFields = new ArrayList<>();
|
||||||
|
xFields.addAll(xAxis);
|
||||||
|
xFields.addAll(extStack);
|
||||||
|
Dimension2SQLObj.dimension2sqlObj(sqlMeta, xFields, transFields(allFields), crossDs, dsMap, Utils.getParams(transFields(allFields)), view.getCalParams(), pluginManage);
|
||||||
|
Quota2SQLObj.quota2sqlObj(sqlMeta, yAxis, transFields(allFields), crossDs, dsMap, Utils.getParams(transFields(allFields)), view.getCalParams(), pluginManage);
|
||||||
|
querySql = SQLProvider.createQuerySQL(sqlMeta, true, needOrder, view);
|
||||||
|
} else if (StringUtils.containsIgnoreCase(view.getType(), "scatter")) {
|
||||||
|
List<ChartViewFieldDTO> yFields = new ArrayList<>();
|
||||||
|
yFields.addAll(yAxis);
|
||||||
|
yFields.addAll(extBubble);
|
||||||
|
Dimension2SQLObj.dimension2sqlObj(sqlMeta, xAxis, transFields(allFields), crossDs, dsMap, Utils.getParams(transFields(allFields)), view.getCalParams(), pluginManage);
|
||||||
|
Quota2SQLObj.quota2sqlObj(sqlMeta, yFields, transFields(allFields), crossDs, dsMap, Utils.getParams(transFields(allFields)), view.getCalParams(), pluginManage);
|
||||||
|
querySql = SQLProvider.createQuerySQL(sqlMeta, true, needOrder, view);
|
||||||
|
} else if (StringUtils.equalsIgnoreCase("table-info", view.getType())) {
|
||||||
|
Dimension2SQLObj.dimension2sqlObj(sqlMeta, xAxis, transFields(allFields), crossDs, dsMap, Utils.getParams(transFields(allFields)), view.getCalParams(), pluginManage);
|
||||||
|
querySql = SQLProvider.createQuerySQL(sqlMeta, false, true, view);
|
||||||
|
} else {
|
||||||
|
Dimension2SQLObj.dimension2sqlObj(sqlMeta, xAxis, transFields(allFields), crossDs, dsMap, Utils.getParams(transFields(allFields)), view.getCalParams(), pluginManage);
|
||||||
|
Quota2SQLObj.quota2sqlObj(sqlMeta, yAxis, transFields(allFields), crossDs, dsMap, Utils.getParams(transFields(allFields)), view.getCalParams(), pluginManage);
|
||||||
|
querySql = SQLProvider.createQuerySQL(sqlMeta, true, needOrder, view);
|
||||||
|
}
|
||||||
|
|
||||||
|
querySql = provider.rebuildSQL(querySql, sqlMeta, crossDs, dsMap);
|
||||||
|
datasourceRequest.setQuery(querySql);
|
||||||
|
logger.debug("calcite chart get field enum sql: " + querySql);
|
||||||
|
|
||||||
|
data = (List<String[]>) provider.fetchResultField(datasourceRequest).get("data");
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
private 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());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void saveChartViewFromVisualization(String checkData, Long sceneId, Map<Long, ChartViewDTO> chartViewsInfo) {
|
||||||
|
if (!MapUtils.isEmpty(chartViewsInfo)) {
|
||||||
|
List<Long> disuseChartIdList = new ArrayList<>();
|
||||||
|
chartViewsInfo.forEach((key, chartViewDTO) -> {
|
||||||
|
if (checkData.contains(chartViewDTO.getId() + "")) {
|
||||||
|
try {
|
||||||
|
chartViewDTO.setSceneId(sceneId);
|
||||||
|
chartViewManege.save(chartViewDTO);
|
||||||
|
} catch (Exception e) {
|
||||||
|
DEException.throwException(e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
disuseChartIdList.add(chartViewDTO.getId());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (CollectionUtils.isNotEmpty(disuseChartIdList)) {
|
||||||
|
chartViewManege.disuse(disuseChartIdList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getDrillFieldData(ChartViewDTO view, Long fieldId) throws Exception {
|
||||||
|
List<ChartViewFieldDTO> drillField = view.getDrillFields();
|
||||||
|
ChartViewFieldDTO targetField = null;
|
||||||
|
for (int i = 0; i < drillField.size(); i++) {
|
||||||
|
ChartViewFieldDTO tmp = drillField.get(i);
|
||||||
|
if (tmp.getId().equals(fieldId)) {
|
||||||
|
targetField = tmp;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (targetField == null) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
view.setXAxis(Collections.singletonList(targetField));
|
||||||
|
|
||||||
|
List<String[]> sqlData = sqlData(view, view.getChartExtRequest(), fieldId);
|
||||||
|
List<String[]> result = customSort(Optional.ofNullable(targetField.getCustomSort()).orElse(new ArrayList<>()), sqlData, 0);
|
||||||
|
return result.stream().map(i -> i[0]).distinct().collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,82 @@
|
|||||||
|
package io.dataease.chart.manage;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
|
import io.dataease.dataset.dao.auto.entity.CoreDatasetTableField;
|
||||||
|
import io.dataease.dataset.dao.auto.mapper.CoreDatasetTableFieldMapper;
|
||||||
|
import io.dataease.engine.utils.SQLUtils;
|
||||||
|
import io.dataease.extensions.datasource.dto.CalParam;
|
||||||
|
import io.dataease.extensions.datasource.dto.DatasetTableFieldDTO;
|
||||||
|
import io.dataease.extensions.datasource.dto.FieldGroupDTO;
|
||||||
|
import io.dataease.extensions.view.filter.FilterTreeItem;
|
||||||
|
import io.dataease.extensions.view.filter.FilterTreeObj;
|
||||||
|
import io.dataease.utils.BeanUtils;
|
||||||
|
import io.dataease.utils.JsonUtil;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author Junjun
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class ChartFilterTreeService {
|
||||||
|
@Resource
|
||||||
|
private CoreDatasetTableFieldMapper coreDatasetTableFieldMapper;
|
||||||
|
|
||||||
|
public void searchFieldAndSet(FilterTreeObj tree) {
|
||||||
|
if (ObjectUtils.isNotEmpty(tree)) {
|
||||||
|
if (ObjectUtils.isNotEmpty(tree.getItems())) {
|
||||||
|
for (FilterTreeItem item : tree.getItems()) {
|
||||||
|
if (ObjectUtils.isNotEmpty(item)) {
|
||||||
|
if (StringUtils.equalsIgnoreCase(item.getType(), "item") || ObjectUtils.isEmpty(item.getSubTree())) {
|
||||||
|
CoreDatasetTableField coreDatasetTableField = coreDatasetTableFieldMapper.selectById(item.getFieldId());
|
||||||
|
DatasetTableFieldDTO dto = new DatasetTableFieldDTO();
|
||||||
|
BeanUtils.copyBean(dto, coreDatasetTableField);
|
||||||
|
if (StringUtils.isNotEmpty(coreDatasetTableField.getParams())) {
|
||||||
|
TypeReference<List<CalParam>> tokenType = new TypeReference<>() {
|
||||||
|
};
|
||||||
|
List<CalParam> calParams = JsonUtil.parseList(coreDatasetTableField.getParams(), tokenType);
|
||||||
|
dto.setParams(calParams);
|
||||||
|
}
|
||||||
|
if (StringUtils.isNotEmpty(coreDatasetTableField.getGroupList())) {
|
||||||
|
TypeReference<List<FieldGroupDTO>> groupTokenType = new TypeReference<>() {
|
||||||
|
};
|
||||||
|
List<FieldGroupDTO> fieldGroups = JsonUtil.parseList(coreDatasetTableField.getGroupList(), groupTokenType);
|
||||||
|
dto.setGroupList(fieldGroups);
|
||||||
|
}
|
||||||
|
item.setField(dto);
|
||||||
|
} else if (StringUtils.equalsIgnoreCase(item.getType(), "tree") || (ObjectUtils.isNotEmpty(item.getSubTree()) && StringUtils.isNotEmpty(item.getSubTree().getLogic()))) {
|
||||||
|
searchFieldAndSet(item.getSubTree());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public FilterTreeObj charReplace(FilterTreeObj tree) {
|
||||||
|
if (ObjectUtils.isNotEmpty(tree)) {
|
||||||
|
if (ObjectUtils.isNotEmpty(tree.getItems())) {
|
||||||
|
for (FilterTreeItem item : tree.getItems()) {
|
||||||
|
if (ObjectUtils.isNotEmpty(item)) {
|
||||||
|
if (StringUtils.equalsIgnoreCase(item.getType(), "item") || ObjectUtils.isEmpty(item.getSubTree())) {
|
||||||
|
if (CollectionUtils.isNotEmpty(item.getEnumValue())) {
|
||||||
|
List<String> collect = item.getEnumValue().stream().map(SQLUtils::transKeyword).collect(Collectors.toList());
|
||||||
|
item.setEnumValue(collect);
|
||||||
|
}
|
||||||
|
item.setValue(SQLUtils.transKeyword(item.getValue()));
|
||||||
|
} else if (StringUtils.equalsIgnoreCase(item.getType(), "tree") || (ObjectUtils.isNotEmpty(item.getSubTree()) && StringUtils.isNotEmpty(item.getSubTree().getLogic()))) {
|
||||||
|
charReplace(item.getSubTree());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tree;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,468 @@
|
|||||||
|
package io.dataease.chart.manage;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
|
||||||
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import io.dataease.api.chart.vo.ChartBaseVO;
|
||||||
|
import io.dataease.api.chart.vo.ViewSelectorVO;
|
||||||
|
import io.dataease.chart.dao.auto.entity.CoreChartView;
|
||||||
|
import io.dataease.chart.dao.auto.mapper.CoreChartViewMapper;
|
||||||
|
import io.dataease.chart.dao.ext.entity.ChartBasePO;
|
||||||
|
import io.dataease.chart.dao.ext.mapper.ExtChartViewMapper;
|
||||||
|
import io.dataease.dataset.dao.auto.entity.CoreDatasetTableField;
|
||||||
|
import io.dataease.dataset.dao.auto.mapper.CoreDatasetTableFieldMapper;
|
||||||
|
import io.dataease.dataset.manage.DatasetTableFieldManage;
|
||||||
|
import io.dataease.dataset.manage.PermissionManage;
|
||||||
|
import io.dataease.dataset.utils.TableUtils;
|
||||||
|
import io.dataease.engine.constant.ExtFieldConstant;
|
||||||
|
import io.dataease.engine.func.FunctionConstant;
|
||||||
|
import io.dataease.engine.utils.Utils;
|
||||||
|
import io.dataease.exception.DEException;
|
||||||
|
import io.dataease.extensions.datasource.api.PluginManageApi;
|
||||||
|
import io.dataease.extensions.datasource.dto.CalParam;
|
||||||
|
import io.dataease.extensions.datasource.dto.DatasetTableFieldDTO;
|
||||||
|
import io.dataease.extensions.datasource.dto.FieldGroupDTO;
|
||||||
|
import io.dataease.extensions.datasource.model.SQLObj;
|
||||||
|
import io.dataease.extensions.view.dto.*;
|
||||||
|
import io.dataease.extensions.view.filter.FilterTreeObj;
|
||||||
|
import io.dataease.i18n.Translator;
|
||||||
|
import io.dataease.license.config.XpackInteract;
|
||||||
|
import io.dataease.utils.BeanUtils;
|
||||||
|
import io.dataease.utils.IDUtils;
|
||||||
|
import io.dataease.utils.JsonUtil;
|
||||||
|
import io.dataease.utils.LogUtil;
|
||||||
|
import io.dataease.visualization.dao.auto.entity.DataVisualizationInfo;
|
||||||
|
import io.dataease.visualization.dao.auto.mapper.DataVisualizationInfoMapper;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author Junjun
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class ChartViewManege {
|
||||||
|
@Resource
|
||||||
|
private CoreChartViewMapper coreChartViewMapper;
|
||||||
|
@Resource
|
||||||
|
private ChartDataManage chartDataManage;
|
||||||
|
@Resource
|
||||||
|
private CoreDatasetTableFieldMapper coreDatasetTableFieldMapper;
|
||||||
|
@Resource
|
||||||
|
private PermissionManage permissionManage;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private DataVisualizationInfoMapper visualizationInfoMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ExtChartViewMapper extChartViewMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private DatasetTableFieldManage datasetTableFieldManage;
|
||||||
|
@Autowired(required = false)
|
||||||
|
private PluginManageApi pluginManage;
|
||||||
|
|
||||||
|
private ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public ChartViewDTO save(ChartViewDTO chartViewDTO) throws Exception {
|
||||||
|
if (chartViewDTO.getTitle().length() > 100) {
|
||||||
|
DEException.throwException(Translator.get("i18n_name_limit_100"));
|
||||||
|
}
|
||||||
|
Long id = chartViewDTO.getId();
|
||||||
|
if (id == null) {
|
||||||
|
DEException.throwException(Translator.get("i18n_no_id"));
|
||||||
|
}
|
||||||
|
CoreChartView coreChartView = coreChartViewMapper.selectById(id);
|
||||||
|
CoreChartView record = transDTO2Record(chartViewDTO);
|
||||||
|
if (ObjectUtils.isEmpty(coreChartView)) {
|
||||||
|
coreChartViewMapper.insert(record);
|
||||||
|
} else {
|
||||||
|
UpdateWrapper<CoreChartView> updateWrapper = new UpdateWrapper<>();
|
||||||
|
updateWrapper.eq("id", record.getId());
|
||||||
|
//富文本允许设置空的tableId 这里额外更新一下
|
||||||
|
if (record.getTableId() == null) {
|
||||||
|
updateWrapper.set("table_id", null);
|
||||||
|
}
|
||||||
|
coreChartViewMapper.update(record, updateWrapper);
|
||||||
|
}
|
||||||
|
return chartViewDTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void delete(Long id) {
|
||||||
|
coreChartViewMapper.deleteById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@XpackInteract(value = "chartViewManage")
|
||||||
|
public void disuse(List<Long> chartIdList) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public void deleteBySceneId(Long sceneId, List<Long> chartIds) {
|
||||||
|
QueryWrapper<CoreChartView> wrapper = new QueryWrapper<>();
|
||||||
|
wrapper.eq("scene_id", sceneId);
|
||||||
|
wrapper.notIn("id", chartIds);
|
||||||
|
coreChartViewMapper.delete(wrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ChartViewDTO getDetails(Long id) {
|
||||||
|
CoreChartView coreChartView = coreChartViewMapper.selectById(id);
|
||||||
|
if (ObjectUtils.isEmpty(coreChartView)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ChartViewDTO dto = transRecord2DTO(coreChartView);
|
||||||
|
return dto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sceneId 为仪表板或者数据大屏id
|
||||||
|
*/
|
||||||
|
public List<ChartViewDTO> listBySceneId(Long sceneId) {
|
||||||
|
QueryWrapper<CoreChartView> wrapper = new QueryWrapper<>();
|
||||||
|
wrapper.eq("scene_id", sceneId);
|
||||||
|
List<ChartViewDTO> chartViewDTOS = transChart(coreChartViewMapper.selectList(wrapper));
|
||||||
|
if (!CollectionUtils.isEmpty(chartViewDTOS)) {
|
||||||
|
List<Long> tableIds = chartViewDTOS.stream()
|
||||||
|
.map(ChartViewDTO::getTableId)
|
||||||
|
.filter(tableId -> tableId != null) // 过滤掉空值
|
||||||
|
.distinct()
|
||||||
|
.toList();
|
||||||
|
if (!CollectionUtils.isEmpty(tableIds)) {
|
||||||
|
QueryWrapper<CoreDatasetTableField> wp = new QueryWrapper<>();
|
||||||
|
wp.in("dataset_group_id", tableIds);
|
||||||
|
List<CoreDatasetTableField> coreDatasetTableFields = coreDatasetTableFieldMapper.selectList(wp);
|
||||||
|
Map<Long, List<CoreDatasetTableField>> groupedByTableId = coreDatasetTableFields.stream()
|
||||||
|
.collect(Collectors.groupingBy(CoreDatasetTableField::getDatasetGroupId));
|
||||||
|
if (chartViewDTOS.size() < 10) {
|
||||||
|
chartViewDTOS.forEach(dto -> {
|
||||||
|
if (dto.getTableId() != null) {
|
||||||
|
dto.setCalParams(Utils.getParams(datasetTableFieldManage.transDTO(groupedByTableId.get(dto.getTableId()))));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
ExecutorService executor = Executors.newFixedThreadPool(10);
|
||||||
|
try {
|
||||||
|
// 超过10个图表要处理启用多线程处理
|
||||||
|
CountDownLatch latch = new CountDownLatch(chartViewDTOS.size());
|
||||||
|
chartViewDTOS.forEach(dto -> {
|
||||||
|
executor.submit(() -> {
|
||||||
|
try {
|
||||||
|
if (dto.getTableId() != null) {
|
||||||
|
dto.setCalParams(Utils.getParams(datasetTableFieldManage.transDTO(groupedByTableId.get(dto.getTableId()))));
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
latch.countDown(); // 减少计数器
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 等待所有线程完成
|
||||||
|
boolean completedInTime = latch.await(200, TimeUnit.SECONDS);
|
||||||
|
if (!completedInTime) {
|
||||||
|
throw new InterruptedException("Tasks did not complete within 200 seconds");
|
||||||
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
LogUtil.error(e);
|
||||||
|
} finally {
|
||||||
|
executor.shutdown(); // 确保线程池关闭
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return chartViewDTOS;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ChartViewDTO> transChart(List<CoreChartView> list) {
|
||||||
|
if (ObjectUtils.isEmpty(list)) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
return list.stream().map(ele -> {
|
||||||
|
ChartViewDTO dto = transRecord2DTO(ele);
|
||||||
|
return dto;
|
||||||
|
}).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public ChartViewDTO getChart(Long id) throws Exception {
|
||||||
|
ChartViewDTO details = getDetails(id);
|
||||||
|
if (details == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return chartDataManage.calcData(details);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, List<ChartViewFieldDTO>> listByDQ(Long id, Long chartId, ChartViewDTO chartViewDTO) {
|
||||||
|
QueryWrapper<CoreDatasetTableField> wrapper = new QueryWrapper<>();
|
||||||
|
wrapper.eq("dataset_group_id", id);
|
||||||
|
wrapper.eq("checked", true);
|
||||||
|
wrapper.isNull("chart_id");
|
||||||
|
|
||||||
|
TypeReference<List<CalParam>> typeToken = new TypeReference<>() {
|
||||||
|
};
|
||||||
|
TypeReference<List<FieldGroupDTO>> groupTokenType = new TypeReference<>() {
|
||||||
|
};
|
||||||
|
List<CoreDatasetTableField> fields = coreDatasetTableFieldMapper.selectList(wrapper);
|
||||||
|
List<DatasetTableFieldDTO> collect = fields.stream().map(ele -> {
|
||||||
|
DatasetTableFieldDTO dto = new DatasetTableFieldDTO();
|
||||||
|
BeanUtils.copyBean(dto, ele);
|
||||||
|
dto.setParams(JsonUtil.parseList(ele.getParams(), typeToken));
|
||||||
|
dto.setGroupList(JsonUtil.parseList(ele.getGroupList(), groupTokenType));
|
||||||
|
return dto;
|
||||||
|
}).collect(Collectors.toList());
|
||||||
|
// filter column disable field
|
||||||
|
Map<String, ColumnPermissionItem> desensitizationList = new HashMap<>();
|
||||||
|
List<DatasetTableFieldDTO> datasetTableFieldDTOS = permissionManage.filterColumnPermissions(collect, desensitizationList, id, null);
|
||||||
|
datasetTableFieldDTOS.forEach(ele -> ele.setDesensitized(desensitizationList.containsKey(ele.getDataeaseName())));
|
||||||
|
datasetTableFieldDTOS.add(createCountField(id));
|
||||||
|
List<ChartViewFieldDTO> list = transFieldDTO(datasetTableFieldDTOS);
|
||||||
|
|
||||||
|
// 获取图表计算字段
|
||||||
|
wrapper.clear();
|
||||||
|
wrapper.eq("chart_id", chartId);
|
||||||
|
List<DatasetTableFieldDTO> chartFields = coreDatasetTableFieldMapper.selectList(wrapper).stream().map(ele -> {
|
||||||
|
DatasetTableFieldDTO dto = new DatasetTableFieldDTO();
|
||||||
|
BeanUtils.copyBean(dto, ele);
|
||||||
|
dto.setGroupList(JsonUtil.parseList(ele.getGroupList(), groupTokenType));
|
||||||
|
return dto;
|
||||||
|
}).collect(Collectors.toList());
|
||||||
|
list.addAll(transFieldDTO(chartFields));
|
||||||
|
|
||||||
|
// 获取list中的聚合函数,将字段的summary设置成空
|
||||||
|
SQLObj tableObj = new SQLObj();
|
||||||
|
tableObj.setTableAlias("");
|
||||||
|
|
||||||
|
for (ChartViewFieldDTO ele : list) {
|
||||||
|
if (Objects.equals(ele.getExtField(), ExtFieldConstant.EXT_CALC)) {
|
||||||
|
List<DatasetTableFieldDTO> f = list.stream().map(e -> {
|
||||||
|
DatasetTableFieldDTO dto = new DatasetTableFieldDTO();
|
||||||
|
BeanUtils.copyBean(dto, e);
|
||||||
|
return dto;
|
||||||
|
}).collect(Collectors.toList());
|
||||||
|
String originField = Utils.calcFieldRegex(ele, tableObj, f, true, null, Utils.mergeParam(Utils.getParams(f), null), pluginManage);
|
||||||
|
for (String func : FunctionConstant.AGG_FUNC) {
|
||||||
|
if (Utils.matchFunction(func, originField)) {
|
||||||
|
ele.setSummary("");
|
||||||
|
ele.setAgg(true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<ChartViewFieldDTO> dimensionList = list.stream().filter(ele -> StringUtils.equalsIgnoreCase(ele.getGroupType(), "d")).collect(Collectors.toList());
|
||||||
|
List<ChartViewFieldDTO> quotaList = list.stream().filter(ele -> StringUtils.equalsIgnoreCase(ele.getGroupType(), "q")).collect(Collectors.toList());
|
||||||
|
|
||||||
|
Map<String, List<ChartViewFieldDTO>> map = new LinkedHashMap<>();
|
||||||
|
map.put("dimensionList", dimensionList);
|
||||||
|
map.put("quotaList", quotaList);
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void copyField(Long id, Long chartId) {
|
||||||
|
CoreDatasetTableField coreDatasetTableField = coreDatasetTableFieldMapper.selectById(id);
|
||||||
|
QueryWrapper<CoreDatasetTableField> queryWrapper = new QueryWrapper<>();
|
||||||
|
queryWrapper.eq("dataset_group_id", coreDatasetTableField.getDatasetGroupId());
|
||||||
|
List<CoreDatasetTableField> coreDatasetTableFields = coreDatasetTableFieldMapper.selectList(queryWrapper);
|
||||||
|
HashMap<String, String> map = new HashMap<>();
|
||||||
|
for (CoreDatasetTableField ele : coreDatasetTableFields) {
|
||||||
|
map.put(ele.getName(), ele.getName());
|
||||||
|
}
|
||||||
|
newName(map, coreDatasetTableField, coreDatasetTableField.getName());
|
||||||
|
coreDatasetTableField.setChartId(chartId);
|
||||||
|
coreDatasetTableField.setExtField(2);
|
||||||
|
coreDatasetTableField.setOriginName("[" + id + "]");
|
||||||
|
coreDatasetTableField.setId(IDUtils.snowID());
|
||||||
|
coreDatasetTableField.setDataeaseName(TableUtils.fieldNameShort(coreDatasetTableField.getId() + "_" + coreDatasetTableField.getOriginName()));
|
||||||
|
coreDatasetTableField.setFieldShortName(coreDatasetTableField.getDataeaseName());
|
||||||
|
coreDatasetTableFieldMapper.insert(coreDatasetTableField);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void newName(HashMap<String, String> map, CoreDatasetTableField coreDatasetTableField, String name) {
|
||||||
|
name = name + "_copy";
|
||||||
|
if (map.containsKey(name)) {
|
||||||
|
newName(map, coreDatasetTableField, name);
|
||||||
|
} else {
|
||||||
|
coreDatasetTableField.setName(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deleteField(Long id) {
|
||||||
|
coreDatasetTableFieldMapper.deleteById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deleteFieldByChartId(Long chartId) {
|
||||||
|
QueryWrapper<CoreDatasetTableField> queryWrapper = new QueryWrapper<>();
|
||||||
|
queryWrapper.eq("chart_id", chartId);
|
||||||
|
coreDatasetTableFieldMapper.delete(queryWrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ChartBaseVO chartBaseInfo(Long id) {
|
||||||
|
ChartBasePO po = extChartViewMapper.queryChart(id);
|
||||||
|
if (ObjectUtils.isEmpty(po)) return null;
|
||||||
|
ChartBaseVO vo = BeanUtils.copyBean(new ChartBaseVO(), po);
|
||||||
|
TypeReference<List<ChartViewFieldDTO>> tokenType = new TypeReference<>() {
|
||||||
|
};
|
||||||
|
vo.setXAxis(JsonUtil.parseList(po.getXAxis(), tokenType));
|
||||||
|
vo.setXAxisExt(JsonUtil.parseList(po.getXAxisExt(), tokenType));
|
||||||
|
vo.setYAxis(JsonUtil.parseList(po.getYAxis(), tokenType));
|
||||||
|
vo.setYAxisExt(JsonUtil.parseList(po.getYAxisExt(), tokenType));
|
||||||
|
vo.setExtStack(JsonUtil.parseList(po.getExtStack(), tokenType));
|
||||||
|
vo.setExtBubble(JsonUtil.parseList(po.getExtBubble(), tokenType));
|
||||||
|
vo.setFlowMapStartName(JsonUtil.parseList(po.getFlowMapStartName(), tokenType));
|
||||||
|
vo.setFlowMapEndName(JsonUtil.parseList(po.getFlowMapEndName(), tokenType));
|
||||||
|
if (StringUtils.isBlank(po.getExtColor()) || StringUtils.equals("null", po.getExtColor())) {
|
||||||
|
vo.setExtColor(new ArrayList<>());
|
||||||
|
} else {
|
||||||
|
vo.setExtColor(JsonUtil.parseList(po.getExtColor(), tokenType));
|
||||||
|
}
|
||||||
|
vo.setExtLabel(JsonUtil.parseList(po.getExtLabel(), tokenType));
|
||||||
|
vo.setExtTooltip(JsonUtil.parseList(po.getExtTooltip(), tokenType));
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DatasetTableFieldDTO createCountField(Long id) {
|
||||||
|
DatasetTableFieldDTO dto = new DatasetTableFieldDTO();
|
||||||
|
dto.setId(-1L);
|
||||||
|
dto.setDatasetGroupId(id);
|
||||||
|
dto.setOriginName("*");
|
||||||
|
dto.setName("记录数*");
|
||||||
|
dto.setDataeaseName("*");
|
||||||
|
dto.setType("INT");
|
||||||
|
dto.setChecked(true);
|
||||||
|
dto.setColumnIndex(999);
|
||||||
|
dto.setDeType(2);
|
||||||
|
dto.setExtField(1);
|
||||||
|
dto.setGroupType("q");
|
||||||
|
return dto;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ChartViewFieldDTO> transFieldDTO(List<DatasetTableFieldDTO> list) {
|
||||||
|
return list.stream().map(ele -> {
|
||||||
|
ChartViewFieldDTO dto = new ChartViewFieldDTO();
|
||||||
|
if (ele == null) return null;
|
||||||
|
BeanUtils.copyBean(dto, ele);
|
||||||
|
dto.setDateStyle("y_M_d");
|
||||||
|
dto.setDatePattern("date_sub");
|
||||||
|
dto.setChartType("bar");
|
||||||
|
|
||||||
|
if (dto.getId() == -1L || dto.getDeType() == 0 || dto.getDeType() == 1 || dto.getDeType() == 7) {
|
||||||
|
dto.setSummary("count");
|
||||||
|
} else {
|
||||||
|
dto.setSummary("sum");
|
||||||
|
}
|
||||||
|
|
||||||
|
ChartFieldCompareDTO chartFieldCompareDTO = new ChartFieldCompareDTO();
|
||||||
|
chartFieldCompareDTO.setType("none");
|
||||||
|
dto.setCompareCalc(chartFieldCompareDTO);
|
||||||
|
|
||||||
|
dto.setFormatterCfg(new FormatterCfgDTO());
|
||||||
|
|
||||||
|
dto.setSort("none");
|
||||||
|
dto.setFilter(Collections.emptyList());
|
||||||
|
return dto;
|
||||||
|
}).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public CoreChartView transDTO2Record(ChartViewDTO dto) throws Exception {
|
||||||
|
CoreChartView record = new CoreChartView();
|
||||||
|
BeanUtils.copyBean(record, dto);
|
||||||
|
|
||||||
|
record.setxAxis(objectMapper.writeValueAsString(dto.getXAxis()));
|
||||||
|
record.setxAxisExt(objectMapper.writeValueAsString(dto.getXAxisExt()));
|
||||||
|
record.setyAxis(objectMapper.writeValueAsString(dto.getYAxis()));
|
||||||
|
record.setyAxisExt(objectMapper.writeValueAsString(dto.getYAxisExt()));
|
||||||
|
record.setExtStack(objectMapper.writeValueAsString(dto.getExtStack()));
|
||||||
|
record.setExtBubble(objectMapper.writeValueAsString(dto.getExtBubble()));
|
||||||
|
record.setExtLabel(objectMapper.writeValueAsString(dto.getExtLabel()));
|
||||||
|
record.setExtTooltip(objectMapper.writeValueAsString(dto.getExtTooltip()));
|
||||||
|
record.setCustomAttr(objectMapper.writeValueAsString(dto.getCustomAttr()));
|
||||||
|
if (dto.getCustomAttrMobile() != null) {
|
||||||
|
record.setCustomAttrMobile(objectMapper.writeValueAsString(dto.getCustomAttrMobile()));
|
||||||
|
}
|
||||||
|
record.setCustomStyle(objectMapper.writeValueAsString(dto.getCustomStyle()));
|
||||||
|
if (dto.getCustomAttrMobile() != null) {
|
||||||
|
record.setCustomStyleMobile(objectMapper.writeValueAsString(dto.getCustomStyleMobile()));
|
||||||
|
}
|
||||||
|
record.setSenior(objectMapper.writeValueAsString(dto.getSenior()));
|
||||||
|
record.setDrillFields(objectMapper.writeValueAsString(dto.getDrillFields()));
|
||||||
|
record.setCustomFilter(objectMapper.writeValueAsString(dto.getCustomFilter()));
|
||||||
|
record.setViewFields(objectMapper.writeValueAsString(dto.getViewFields()));
|
||||||
|
record.setFlowMapStartName(objectMapper.writeValueAsString(dto.getFlowMapStartName()));
|
||||||
|
record.setFlowMapEndName(objectMapper.writeValueAsString(dto.getFlowMapEndName()));
|
||||||
|
record.setExtColor(objectMapper.writeValueAsString(dto.getExtColor()));
|
||||||
|
|
||||||
|
return record;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ChartViewDTO transRecord2DTO(CoreChartView record) {
|
||||||
|
ChartViewDTO dto = new ChartViewDTO();
|
||||||
|
BeanUtils.copyBean(dto, record);
|
||||||
|
|
||||||
|
TypeReference<List<ChartViewFieldDTO>> tokenType = new TypeReference<>() {
|
||||||
|
};
|
||||||
|
|
||||||
|
dto.setXAxis(JsonUtil.parseList(record.getxAxis(), tokenType));
|
||||||
|
dto.setXAxisExt(JsonUtil.parseList(record.getxAxisExt(), tokenType));
|
||||||
|
dto.setYAxis(JsonUtil.parseList(record.getyAxis(), tokenType));
|
||||||
|
dto.setYAxisExt(JsonUtil.parseList(record.getyAxisExt(), tokenType));
|
||||||
|
dto.setExtStack(JsonUtil.parseList(record.getExtStack(), tokenType));
|
||||||
|
dto.setExtBubble(JsonUtil.parseList(record.getExtBubble(), tokenType));
|
||||||
|
dto.setExtLabel(JsonUtil.parseList(record.getExtLabel(), tokenType));
|
||||||
|
dto.setExtTooltip(JsonUtil.parseList(record.getExtTooltip(), tokenType));
|
||||||
|
dto.setCustomAttr(JsonUtil.parse(record.getCustomAttr(), Map.class));
|
||||||
|
if (record.getCustomAttrMobile() != null) {
|
||||||
|
dto.setCustomAttrMobile(JsonUtil.parse(record.getCustomAttrMobile(), Map.class));
|
||||||
|
}
|
||||||
|
dto.setCustomStyle(JsonUtil.parse(record.getCustomStyle(), Map.class));
|
||||||
|
if (record.getCustomStyleMobile() != null) {
|
||||||
|
dto.setCustomStyleMobile(JsonUtil.parse(record.getCustomStyleMobile(), Map.class));
|
||||||
|
}
|
||||||
|
dto.setSenior(JsonUtil.parse(record.getSenior(), Map.class));
|
||||||
|
dto.setDrillFields(JsonUtil.parseList(record.getDrillFields(), tokenType));
|
||||||
|
dto.setCustomFilter(JsonUtil.parseObject(record.getCustomFilter(), FilterTreeObj.class));
|
||||||
|
dto.setViewFields(JsonUtil.parseList(record.getViewFields(), tokenType));
|
||||||
|
dto.setFlowMapStartName(JsonUtil.parseList(record.getFlowMapStartName(), tokenType));
|
||||||
|
dto.setFlowMapEndName(JsonUtil.parseList(record.getFlowMapEndName(), tokenType));
|
||||||
|
dto.setExtColor(JsonUtil.parseList(record.getExtColor(), tokenType));
|
||||||
|
|
||||||
|
return dto;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public String checkSameDataSet(String viewIdSource, String viewIdTarget) {
|
||||||
|
QueryWrapper<CoreChartView> wrapper = new QueryWrapper<>();
|
||||||
|
wrapper.select("distinct table_id");
|
||||||
|
wrapper.in("id", Arrays.asList(viewIdSource, viewIdTarget));
|
||||||
|
coreChartViewMapper.selectCount(wrapper);
|
||||||
|
if (coreChartViewMapper.selectCount(wrapper) == 1) {
|
||||||
|
return "YES";
|
||||||
|
} else {
|
||||||
|
return "NO";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ViewSelectorVO> viewOption(Long resourceId) {
|
||||||
|
List<ViewSelectorVO> result = extChartViewMapper.queryViewOption(resourceId);
|
||||||
|
DataVisualizationInfo dvInfo = visualizationInfoMapper.selectById(resourceId);
|
||||||
|
if (dvInfo != null && !CollectionUtils.isEmpty(result)) {
|
||||||
|
String componentData = dvInfo.getComponentData();
|
||||||
|
return result.stream().filter(item -> componentData.indexOf(String.valueOf(item.getId())) > 0).toList();
|
||||||
|
} else {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,205 @@
|
|||||||
|
package io.dataease.chart.manage;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
|
import io.dataease.chart.dao.auto.entity.CoreChartView;
|
||||||
|
import io.dataease.chart.dao.auto.mapper.CoreChartViewMapper;
|
||||||
|
import io.dataease.extensions.view.dto.ChartCustomFilterItemDTO;
|
||||||
|
import io.dataease.extensions.view.dto.ChartFieldCustomFilterDTO;
|
||||||
|
import io.dataease.extensions.view.filter.FilterTreeItem;
|
||||||
|
import io.dataease.extensions.view.filter.FilterTreeObj;
|
||||||
|
import io.dataease.utils.JsonUtil;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author Junjun
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class ChartViewOldDataMergeService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private CoreChartViewMapper coreChartViewMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 视图过滤器重构,合并老数据,将list变成tree
|
||||||
|
*/
|
||||||
|
public void mergeOldData() {
|
||||||
|
// 获取所有视图数据
|
||||||
|
// 把一个视图中的过滤器,即customFilter字段进行重构
|
||||||
|
// 之前是以list形式储存,一个字段是一个item
|
||||||
|
// 现在把一个字段当做tree中的一个节点
|
||||||
|
// 节点中如果是logic且length>1,保留and或or,每一条都变成一个子节点;如果是枚举或只有1条,则当做and处理并保留值
|
||||||
|
// 最后把字段之间通过and的逻辑合并
|
||||||
|
List<CoreChartView> chartViewWithBLOBs = coreChartViewMapper.selectList(new QueryWrapper<>());
|
||||||
|
if (CollectionUtils.isEmpty(chartViewWithBLOBs)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (CoreChartView view : chartViewWithBLOBs) {
|
||||||
|
TypeReference<List<ChartFieldCustomFilterDTO>> tokenType = new TypeReference<>() {
|
||||||
|
};
|
||||||
|
List<ChartFieldCustomFilterDTO> fieldCustomFilter;
|
||||||
|
// 尝试将历史数据转成list,如果转换出现异常,则忽略该视图继续执行下一个
|
||||||
|
try {
|
||||||
|
fieldCustomFilter = JsonUtil.parseList(view.getCustomFilter(), tokenType);
|
||||||
|
} catch (Exception e) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CollectionUtils.isEmpty(fieldCustomFilter)) {
|
||||||
|
// 将 '[]' 转换成 '{}'
|
||||||
|
view.setCustomFilter("{}");
|
||||||
|
} else {
|
||||||
|
// array -> tree
|
||||||
|
FilterTreeObj tree = transArr2Obj(fieldCustomFilter);
|
||||||
|
view.setCustomFilter((String) JsonUtil.toJSONString(tree));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
coreChartViewMapper.updateById(view);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// do nothing,to continue
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public FilterTreeObj transArr2Obj(List<ChartFieldCustomFilterDTO> fieldCustomFilter) {
|
||||||
|
FilterTreeObj tree = new FilterTreeObj();
|
||||||
|
tree.setItems(new ArrayList<>());
|
||||||
|
if (fieldCustomFilter.size() == 1) {
|
||||||
|
ChartFieldCustomFilterDTO filterDTO = fieldCustomFilter.get(0);
|
||||||
|
tree.setLogic(filterDTO.getLogic());
|
||||||
|
if (StringUtils.equalsIgnoreCase(filterDTO.getFilterType(), "enum")) {
|
||||||
|
FilterTreeItem item = new FilterTreeItem();
|
||||||
|
item.setType("item");
|
||||||
|
item.setFieldId(filterDTO.getId());
|
||||||
|
item.setFilterType(filterDTO.getFilterType());
|
||||||
|
item.setEnumValue(filterDTO.getEnumCheckField());
|
||||||
|
tree.getItems().add(item);
|
||||||
|
} else {
|
||||||
|
List<ChartCustomFilterItemDTO> filter = filterDTO.getFilter();
|
||||||
|
if (CollectionUtils.isNotEmpty(filter)) {
|
||||||
|
for (ChartCustomFilterItemDTO f : filter) {
|
||||||
|
FilterTreeItem item = new FilterTreeItem();
|
||||||
|
item.setType("item");
|
||||||
|
item.setFieldId(filterDTO.getId());
|
||||||
|
item.setFilterType(filterDTO.getFilterType());
|
||||||
|
item.setTerm(f.getTerm());
|
||||||
|
item.setValue(f.getValue());
|
||||||
|
item.setEnumValue(new ArrayList<>());
|
||||||
|
tree.getItems().add(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tree.setLogic("and");
|
||||||
|
for (ChartFieldCustomFilterDTO dto : fieldCustomFilter) {
|
||||||
|
if (StringUtils.equalsIgnoreCase(dto.getFilterType(), "enum")) {
|
||||||
|
FilterTreeItem item = new FilterTreeItem();
|
||||||
|
item.setType("item");
|
||||||
|
item.setFieldId(dto.getId());
|
||||||
|
item.setFilterType(dto.getFilterType());
|
||||||
|
item.setEnumValue(dto.getEnumCheckField());
|
||||||
|
tree.getItems().add(item);
|
||||||
|
} else {
|
||||||
|
List<ChartCustomFilterItemDTO> filter = dto.getFilter();
|
||||||
|
if (CollectionUtils.isNotEmpty(filter)) {
|
||||||
|
if (filter.size() == 1) {
|
||||||
|
ChartCustomFilterItemDTO f = filter.get(0);
|
||||||
|
FilterTreeItem item = new FilterTreeItem();
|
||||||
|
item.setType("item");
|
||||||
|
item.setFieldId(dto.getId());
|
||||||
|
item.setFilterType(dto.getFilterType());
|
||||||
|
item.setTerm(f.getTerm());
|
||||||
|
item.setValue(f.getValue());
|
||||||
|
item.setEnumValue(new ArrayList<>());
|
||||||
|
tree.getItems().add(item);
|
||||||
|
} else {
|
||||||
|
FilterTreeItem item = new FilterTreeItem();
|
||||||
|
item.setType("tree");
|
||||||
|
item.setEnumValue(new ArrayList<>());
|
||||||
|
FilterTreeObj subTree = new FilterTreeObj();
|
||||||
|
subTree.setLogic(dto.getLogic());
|
||||||
|
subTree.setItems(new ArrayList<>());
|
||||||
|
for (ChartCustomFilterItemDTO f : filter) {
|
||||||
|
FilterTreeItem itemTree = new FilterTreeItem();
|
||||||
|
itemTree.setType("item");
|
||||||
|
itemTree.setFieldId(dto.getId());
|
||||||
|
itemTree.setFilterType(dto.getFilterType());
|
||||||
|
itemTree.setTerm(f.getTerm());
|
||||||
|
itemTree.setValue(f.getValue());
|
||||||
|
itemTree.setEnumValue(new ArrayList<>());
|
||||||
|
subTree.getItems().add(itemTree);
|
||||||
|
}
|
||||||
|
item.setSubTree(subTree);
|
||||||
|
tree.getItems().add(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tree;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 视图过滤器动态时间兼容老数据
|
||||||
|
*/
|
||||||
|
public void refreshFilter() {
|
||||||
|
// 获取所有视图数据
|
||||||
|
// 在filter中增加filterTypeTime = dateValue
|
||||||
|
List<CoreChartView> chartViewWithBLOBs = coreChartViewMapper.selectList(new QueryWrapper<>());
|
||||||
|
if (CollectionUtils.isEmpty(chartViewWithBLOBs)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (CoreChartView view : chartViewWithBLOBs) {
|
||||||
|
FilterTreeObj filterTreeObj;
|
||||||
|
try {
|
||||||
|
filterTreeObj = JsonUtil.parseObject(view.getCustomFilter(), FilterTreeObj.class);
|
||||||
|
} catch (Exception e) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ObjectUtils.isNotEmpty(filterTreeObj)) {
|
||||||
|
if (ObjectUtils.isEmpty(filterTreeObj.getItems())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
FilterTreeObj tree = fixFilter(filterTreeObj);
|
||||||
|
view.setCustomFilter((String) JsonUtil.toJSONString(tree));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
coreChartViewMapper.updateById(view);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// do nothing,to continue
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public FilterTreeObj fixFilter(FilterTreeObj filterTreeObj) {
|
||||||
|
doFix(filterTreeObj.getItems());
|
||||||
|
return filterTreeObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doFix(List<FilterTreeItem> items) {
|
||||||
|
if (ObjectUtils.isEmpty(items)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (FilterTreeItem item : items) {
|
||||||
|
if (StringUtils.equalsIgnoreCase(item.getType(), "item")) {
|
||||||
|
item.setFilterTypeTime("dateValue");
|
||||||
|
} else {
|
||||||
|
doFix(item.getSubTree().getItems());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,582 @@
|
|||||||
|
package io.dataease.chart.manage;
|
||||||
|
|
||||||
|
import io.dataease.api.chart.request.ThresholdCheckRequest;
|
||||||
|
import io.dataease.api.chart.vo.ThresholdCheckVO;
|
||||||
|
import io.dataease.constant.DeTypeConstants;
|
||||||
|
import io.dataease.exception.DEException;
|
||||||
|
import io.dataease.extensions.datasource.dto.DatasetTableFieldDTO;
|
||||||
|
import io.dataease.extensions.view.dto.ChartViewDTO;
|
||||||
|
import io.dataease.extensions.view.dto.ChartViewFieldDTO;
|
||||||
|
import io.dataease.extensions.view.filter.FilterTreeItem;
|
||||||
|
import io.dataease.extensions.view.filter.FilterTreeObj;
|
||||||
|
import io.dataease.i18n.Translator;
|
||||||
|
import io.dataease.utils.DateUtils;
|
||||||
|
import io.dataease.utils.JsonUtil;
|
||||||
|
import io.dataease.utils.LogUtil;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.apache.commons.collections4.MapUtils;
|
||||||
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Component("chartViewThresholdManage")
|
||||||
|
public class ChartViewThresholdManage {
|
||||||
|
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ChartViewManege chartViewManege;
|
||||||
|
|
||||||
|
public String convertThresholdRules(Long chartId, String thresholdRules) {
|
||||||
|
ChartViewDTO details = chartViewManege.getDetails(chartId);
|
||||||
|
return convertThresholdRules(details, thresholdRules);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String convertThresholdRules(ChartViewDTO chart, String thresholdRules) {
|
||||||
|
List<DatasetTableFieldDTO> fieldList = chartFields(chart);
|
||||||
|
FilterTreeObj filterTreeObj = JsonUtil.parseObject(thresholdRules, FilterTreeObj.class);
|
||||||
|
Map<String, DatasetTableFieldDTO> fieldMap = fieldList.stream().collect(Collectors.toMap(item -> item.getId().toString(), item -> item));
|
||||||
|
return convertTree(filterTreeObj, fieldMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<DatasetTableFieldDTO> chartFields(ChartViewDTO details) {
|
||||||
|
List<DatasetTableFieldDTO> result = new ArrayList<>();
|
||||||
|
List<ChartViewFieldDTO> xAxis = details.getXAxis();
|
||||||
|
if (CollectionUtils.isNotEmpty(xAxis)) {
|
||||||
|
result.addAll(xAxis);
|
||||||
|
}
|
||||||
|
List<ChartViewFieldDTO> xAxisExt = details.getXAxisExt();
|
||||||
|
if (CollectionUtils.isNotEmpty(xAxisExt)) {
|
||||||
|
result.addAll(xAxisExt);
|
||||||
|
}
|
||||||
|
List<ChartViewFieldDTO> yAxis = details.getYAxis();
|
||||||
|
if (CollectionUtils.isNotEmpty(yAxis)) {
|
||||||
|
result.addAll(yAxis);
|
||||||
|
}
|
||||||
|
List<ChartViewFieldDTO> yAxisExt = details.getYAxisExt();
|
||||||
|
if (CollectionUtils.isNotEmpty(yAxisExt)) {
|
||||||
|
result.addAll(yAxisExt);
|
||||||
|
}
|
||||||
|
List<ChartViewFieldDTO> extStack = details.getExtStack();
|
||||||
|
if (CollectionUtils.isNotEmpty(extStack)) {
|
||||||
|
result.addAll(extStack);
|
||||||
|
}
|
||||||
|
List<ChartViewFieldDTO> extBubble = details.getExtBubble();
|
||||||
|
if (CollectionUtils.isNotEmpty(extBubble)) {
|
||||||
|
result.addAll(extBubble);
|
||||||
|
}
|
||||||
|
List<ChartViewFieldDTO> extLabel = details.getExtLabel();
|
||||||
|
if (CollectionUtils.isNotEmpty(extLabel)) {
|
||||||
|
result.addAll(extLabel);
|
||||||
|
}
|
||||||
|
List<ChartViewFieldDTO> extTooltip = details.getExtTooltip();
|
||||||
|
if (CollectionUtils.isNotEmpty(extTooltip)) {
|
||||||
|
result.addAll(extTooltip);
|
||||||
|
}
|
||||||
|
List<ChartViewFieldDTO> extColor = details.getExtColor();
|
||||||
|
if (CollectionUtils.isNotEmpty(extColor)) {
|
||||||
|
result.addAll(extColor);
|
||||||
|
}
|
||||||
|
List<ChartViewFieldDTO> flowMapStartName = details.getFlowMapStartName();
|
||||||
|
if (CollectionUtils.isNotEmpty(flowMapStartName)) {
|
||||||
|
result.addAll(flowMapStartName);
|
||||||
|
}
|
||||||
|
List<ChartViewFieldDTO> flowMapEndName = details.getFlowMapEndName();
|
||||||
|
if (CollectionUtils.isNotEmpty(flowMapEndName)) {
|
||||||
|
result.addAll(flowMapEndName);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String convertTree(FilterTreeObj filterTreeObj, Map<String, DatasetTableFieldDTO> fieldMap) {
|
||||||
|
String logic = filterTreeObj.getLogic();
|
||||||
|
String logicText = translateLogic(logic);
|
||||||
|
List<FilterTreeItem> items = filterTreeObj.getItems();
|
||||||
|
|
||||||
|
StringBuilder result = new StringBuilder();
|
||||||
|
for (FilterTreeItem item : items) {
|
||||||
|
String type = item.getType();
|
||||||
|
if (StringUtils.equals("tree", type) && ObjectUtils.isNotEmpty(item.getSubTree())) {
|
||||||
|
String childResult = convertTree(item.getSubTree(), fieldMap);
|
||||||
|
result.append(childResult);
|
||||||
|
} else {
|
||||||
|
String itemResult = convertItem(item, fieldMap);
|
||||||
|
result.append(itemResult);
|
||||||
|
}
|
||||||
|
result.append(logicText);
|
||||||
|
}
|
||||||
|
int lastIndex = -1;
|
||||||
|
if ((!result.isEmpty()) && (lastIndex = result.lastIndexOf(logicText)) > 0) {
|
||||||
|
return result.substring(0, lastIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String convertItem(FilterTreeItem item, Map<String, DatasetTableFieldDTO> fieldMap) {
|
||||||
|
String filterType = item.getFilterType();
|
||||||
|
Long fieldId = item.getFieldId();
|
||||||
|
DatasetTableFieldDTO map = fieldMap.get(fieldId.toString());
|
||||||
|
String fieldName = map.getName();
|
||||||
|
if (StringUtils.equals(filterType, "enum")) {
|
||||||
|
List<String> enumValue = item.getEnumValue();
|
||||||
|
String enumValueText = String.join(",", enumValue);
|
||||||
|
return fieldName + " " + Translator.get("i18n_threshold_logic_in") + " " + "( " + enumValueText + " )";
|
||||||
|
} else {
|
||||||
|
Integer deType = map.getDeType();
|
||||||
|
String valueType = item.getValueType();
|
||||||
|
return fieldName + " " + translateTerm(item.getTerm()) + " " + formatFieldValue(item.getValue(), valueType, deType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String formatFieldValue(String value, String valueType, Integer deType) {
|
||||||
|
if (StringUtils.isBlank(valueType)) {
|
||||||
|
valueType = "fixed";
|
||||||
|
}
|
||||||
|
if (StringUtils.equals("fixed", valueType)) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
if (StringUtils.equals("max", value)) {
|
||||||
|
return Translator.get("i18n_threshold_max");
|
||||||
|
} else if (StringUtils.equals("min", value)) {
|
||||||
|
return Translator.get("i18n_threshold_min");
|
||||||
|
} else if (StringUtils.equals("average", value)) {
|
||||||
|
return Translator.get("i18n_threshold_average");
|
||||||
|
} else if (deType == 1) {
|
||||||
|
return formatDynamicTimeLabel(value);
|
||||||
|
} else {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String formatDynamicTimeLabel(String value) {
|
||||||
|
if (StringUtils.isBlank(value)) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Map map = JsonUtil.parseObject(value, Map.class);
|
||||||
|
String format = map.get("format").toString();
|
||||||
|
int timeFlag = Integer.parseInt(map.get("timeFlag").toString());
|
||||||
|
|
||||||
|
if (timeFlag == 9) {
|
||||||
|
int count = Integer.parseInt(map.get("count").toString());
|
||||||
|
int unit = Integer.parseInt(map.get("unit").toString());
|
||||||
|
int suffix = Integer.parseInt(map.get("suffix").toString());
|
||||||
|
String time = map.get("time").toString();
|
||||||
|
|
||||||
|
List<String> unitLabels = null;
|
||||||
|
if (StringUtils.equalsIgnoreCase("YYYY", format)) {
|
||||||
|
unitLabels = List.of(Translator.get("i18n_time_year"));
|
||||||
|
} else if (StringUtils.equalsIgnoreCase("YYYY-MM", format)) {
|
||||||
|
unitLabels = List.of(Translator.get("i18n_time_year"), Translator.get("i18n_time_month"));
|
||||||
|
} else if (StringUtils.equalsIgnoreCase("YYYY-MM-DD", format)) {
|
||||||
|
unitLabels = List.of(Translator.get("i18n_time_year"), Translator.get("i18n_time_month"), Translator.get("i18n_time_date"));
|
||||||
|
} else if (StringUtils.equalsIgnoreCase("HH:mm:ss", format)) {
|
||||||
|
DEException.throwException("纯时间格式不支持动态格式");
|
||||||
|
} else {
|
||||||
|
unitLabels = List.of(Translator.get("i18n_time_year"), Translator.get("i18n_time_month"), Translator.get("i18n_time_date"));
|
||||||
|
}
|
||||||
|
String unitText = unitLabels.get(unit - 1);
|
||||||
|
String suffixText = Translator.get("i18n_time_ago");
|
||||||
|
if (suffix == 2) {
|
||||||
|
suffixText = Translator.get("i18n_time_later");
|
||||||
|
}
|
||||||
|
String timeText = "";
|
||||||
|
if (StringUtils.containsIgnoreCase(format, "HH")) {
|
||||||
|
timeText = " " + time;
|
||||||
|
}
|
||||||
|
return count + " " + unitText + suffixText + timeText;
|
||||||
|
} else {
|
||||||
|
List<String> shortLabels = null;
|
||||||
|
if (StringUtils.equalsIgnoreCase("YYYY", format)) {
|
||||||
|
shortLabels = List.of(Translator.get("i18n_time_year_current"), Translator.get("i18n_time_year_last"), Translator.get("i18n_time_year_next"));
|
||||||
|
} else if (StringUtils.equalsIgnoreCase("YYYY-MM", format)) {
|
||||||
|
shortLabels = List.of(Translator.get("i18n_time_month_current"), Translator.get("i18n_time_month_last"), Translator.get("i18n_time_month_next"),
|
||||||
|
Translator.get("i18n_time_month_start"), Translator.get("i18n_time_month_end"));
|
||||||
|
} else if (StringUtils.equalsIgnoreCase("YYYY-MM-DD", format)) {
|
||||||
|
shortLabels = List.of(Translator.get("i18n_time_date_current"), Translator.get("i18n_time_date_last"), Translator.get("i18n_time_date_next"),
|
||||||
|
Translator.get("i18n_time_date_start"), Translator.get("i18n_time_date_end"));
|
||||||
|
} else if (StringUtils.equalsIgnoreCase("HH:mm:ss", format)) {
|
||||||
|
shortLabels = List.of("当前", "1小时前", "1小时后");
|
||||||
|
} else {
|
||||||
|
shortLabels = List.of(Translator.get("i18n_time_date_current"), Translator.get("i18n_time_date_last"), Translator.get("i18n_time_date_next"),
|
||||||
|
Translator.get("i18n_time_date_start"), Translator.get("i18n_time_date_end"));
|
||||||
|
}
|
||||||
|
return shortLabels.get(timeFlag - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
LogUtil.error("动态时间配置错误,请重新配置!");
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String translateTerm(String term) {
|
||||||
|
if (StringUtils.equals(term, "not in")) {
|
||||||
|
return Translator.get("i18n_threshold_logic_not_in");
|
||||||
|
} else if (StringUtils.equals(term, "not like")) {
|
||||||
|
return Translator.get("i18n_threshold_logic_not_like");
|
||||||
|
} else {
|
||||||
|
return Translator.get("i18n_threshold_logic_" + term);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String translateLogic(String logic) {
|
||||||
|
if (StringUtils.equals(logic, "and")) return String.format(" %s ", Translator.get("i18n_threshold_logic_and"));
|
||||||
|
return String.format(" %s ", Translator.get("i18n_threshold_logic_or"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String convertStyle(String htmlString) {
|
||||||
|
String regex = "<span\\s+id=\"(changeText-0|changeText-1)\"\\s+style=\"([^\"]*)\">";
|
||||||
|
Pattern pattern = Pattern.compile(regex);
|
||||||
|
Matcher matcher = pattern.matcher(htmlString);
|
||||||
|
if (matcher.find()) {
|
||||||
|
String styleAttribute = matcher.group();
|
||||||
|
String newStyle = styleAttribute.replace("background: #3370FF33", "background: #FFFFFF")
|
||||||
|
.replace("color: #2b5fd9", "color: #000000");
|
||||||
|
return matcher.replaceAll(Matcher.quoteReplacement(newStyle));
|
||||||
|
}
|
||||||
|
return htmlString;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ThresholdCheckVO checkThreshold(ThresholdCheckRequest request) throws Exception {
|
||||||
|
String thresholdTemplate = request.getThresholdTemplate();
|
||||||
|
String thresholdRules = request.getThresholdRules();
|
||||||
|
Long chartId = request.getChartId();
|
||||||
|
try {
|
||||||
|
ChartViewDTO chart = chartViewManege.getChart(chartId);
|
||||||
|
Map<String, Object> data = null;
|
||||||
|
if (ObjectUtils.isEmpty(chart) || MapUtils.isEmpty(data = chart.getData())) {
|
||||||
|
return new ThresholdCheckVO(false, null, "查询图表异常!", null);
|
||||||
|
}
|
||||||
|
thresholdTemplate = thresholdTemplate.replace("[检测时间]", DateUtils.time2String(System.currentTimeMillis()));
|
||||||
|
String s = convertThresholdRules(chart, thresholdRules);
|
||||||
|
thresholdTemplate = convertStyle(thresholdTemplate.replace("[触发告警]", s));
|
||||||
|
List<Map<String, Object>> tableRow = (List<Map<String, Object>>) data.get("tableRow");
|
||||||
|
List<DatasetTableFieldDTO> fields = (List<DatasetTableFieldDTO>) data.get("fields");
|
||||||
|
if (CollectionUtils.isEmpty(fields)) {
|
||||||
|
return new ThresholdCheckVO(false, null, String.format("当前图表类型[%s]暂不支持阈值告警!", chart.getType()), null);
|
||||||
|
}
|
||||||
|
Map<Long, DatasetTableFieldDTO> fieldMap = fields.stream().collect(Collectors.toMap(DatasetTableFieldDTO::getId, item -> item));
|
||||||
|
FilterTreeObj filterTreeObj = JsonUtil.parseObject(thresholdRules, FilterTreeObj.class);
|
||||||
|
List<Map<String, Object>> rows = filterRows(tableRow, filterTreeObj, fieldMap);
|
||||||
|
if (CollectionUtils.isEmpty(rows)) {
|
||||||
|
return new ThresholdCheckVO(false, null, null, null);
|
||||||
|
}
|
||||||
|
String regex = "<span[^>]*id=\"changeText-(-?\\d+)(?!0$)(?!1$)\"[^>]*>.*?</span>";
|
||||||
|
Pattern pattern = Pattern.compile(regex, Pattern.DOTALL);
|
||||||
|
Matcher matcher = pattern.matcher(thresholdTemplate);
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
while (matcher.find()) {
|
||||||
|
long id = Long.parseLong(matcher.group(1));
|
||||||
|
// 根据id从map中获取替换文本
|
||||||
|
DatasetTableFieldDTO fieldDTO = fieldMap.get(id);
|
||||||
|
if (ObjectUtils.isEmpty(fieldDTO)) continue;
|
||||||
|
String fieldDTOName = fieldDTO.getName();
|
||||||
|
String dataeaseName = fieldDTO.getDataeaseName();
|
||||||
|
List<String> valueList = rows.stream().map(row -> ObjectUtils.isEmpty(row.get(dataeaseName)) ? null : row.get(dataeaseName).toString()).collect(Collectors.toList());
|
||||||
|
String replacement = fieldDTOName + ": " + JsonUtil.toJSONString(valueList);
|
||||||
|
// 替换文本
|
||||||
|
matcher.appendReplacement(sb, replacement);
|
||||||
|
}
|
||||||
|
matcher.appendTail(sb);
|
||||||
|
|
||||||
|
// 输出替换后的HTML内容
|
||||||
|
String result = sb.toString();
|
||||||
|
return new ThresholdCheckVO(true, result, null, null);
|
||||||
|
} catch (Exception e) {
|
||||||
|
LogUtil.error(e.getMessage(), new Throwable(e));
|
||||||
|
return new ThresholdCheckVO(false, null, e.getMessage(), null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void chartDynamicMap(List<Map<String, Object>> rows, FilterTreeObj conditionTree, Map<Long, DatasetTableFieldDTO> fieldMap) {
|
||||||
|
List<FilterTreeItem> items = conditionTree.getItems();
|
||||||
|
items.forEach(item -> {
|
||||||
|
if (!StringUtils.equals("item", item.getType())) {
|
||||||
|
chartDynamicMap(rows, item.getSubTree(), fieldMap);
|
||||||
|
} else {
|
||||||
|
Long fieldId = item.getFieldId();
|
||||||
|
DatasetTableFieldDTO fieldDTO = fieldMap.get(fieldId);
|
||||||
|
if ((Objects.equals(fieldDTO.getDeType(), DeTypeConstants.DE_INT) || Objects.equals(fieldDTO.getDeType(), DeTypeConstants.DE_FLOAT)) && StringUtils.equals("dynamic", item.getValueType())) {
|
||||||
|
item.setField(fieldDTO);
|
||||||
|
item.setValue(formatValue(rows, item));
|
||||||
|
} else if (Objects.equals(fieldDTO.getDeType(), DeTypeConstants.DE_TIME) && StringUtils.equals("dynamic", item.getValueType())) {
|
||||||
|
item.setField(fieldDTO);
|
||||||
|
item.setValue(dynamicFormatValue(item));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private String dynamicFormatValue(FilterTreeItem item) {
|
||||||
|
String value = item.getValue();
|
||||||
|
|
||||||
|
if (StringUtils.isBlank(value)) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Map map = JsonUtil.parseObject(value, Map.class);
|
||||||
|
String format = map.get("format").toString();
|
||||||
|
int timeFlag = Integer.parseInt(map.get("timeFlag").toString());
|
||||||
|
if (timeFlag == 9) {
|
||||||
|
int count = Integer.parseInt(map.get("count").toString());
|
||||||
|
int unit = Integer.parseInt(map.get("unit").toString());
|
||||||
|
int suffix = Integer.parseInt(map.get("suffix").toString());
|
||||||
|
String time = map.get("time").toString();
|
||||||
|
String timeValue = getCustomTimeValue(format, unit, suffix, count, false);
|
||||||
|
if (StringUtils.containsIgnoreCase(format, "yyyy-MM-dd HH") && StringUtils.isNotBlank(time)) {
|
||||||
|
return timeValue + " " + time;
|
||||||
|
}
|
||||||
|
return timeValue;
|
||||||
|
} else {
|
||||||
|
LocalDateTime now = LocalDateTime.now();
|
||||||
|
String fullFormat = "yyyy-MM-dd HH:mm:ss";
|
||||||
|
int length = format.length();
|
||||||
|
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(fullFormat.substring(0, length));
|
||||||
|
int count = timeFlag == 1 ? 0 : 1;
|
||||||
|
int suffix = timeFlag - 1;
|
||||||
|
if (StringUtils.equalsIgnoreCase("YYYY", format)) {
|
||||||
|
return getCustomTimeValue(format, 1, suffix, count, true);
|
||||||
|
} else if (StringUtils.equalsIgnoreCase("YYYY-MM", format)) {
|
||||||
|
if (timeFlag == 4) {
|
||||||
|
return now.withMonth(1).withDayOfMonth(1).format(formatter);
|
||||||
|
} else if (timeFlag == 5) {
|
||||||
|
return now.withMonth(12).withDayOfMonth(31).format(formatter);
|
||||||
|
} else {
|
||||||
|
return getCustomTimeValue(format, 2, suffix, count, true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (timeFlag == 4) {
|
||||||
|
return now.withDayOfMonth(1).withHour(0).withMinute(0).withSecond(0).format(formatter);
|
||||||
|
} else if (timeFlag == 5) {
|
||||||
|
return now.plusMonths(1).withDayOfMonth(1).minusDays(1).withHour(0).withMinute(0).withSecond(0).format(formatter);
|
||||||
|
} else {
|
||||||
|
return getCustomTimeValue(format, 3, suffix, count, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
LogUtil.error("动态时间配置错误,请重新配置!" + e.getMessage());
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getCustomTimeValue(String format, int unit, int suffix, int count, boolean hasTime) {
|
||||||
|
LocalDateTime now = LocalDateTime.now();
|
||||||
|
String fullFormat = "yyyy-MM-dd HH:mm:ss";
|
||||||
|
int len = format.length();
|
||||||
|
if (hasTime) {
|
||||||
|
now = now.withHour(0).withMinute(0).withSecond(0);
|
||||||
|
} else {
|
||||||
|
len = Math.min(len, 10);
|
||||||
|
}
|
||||||
|
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(fullFormat.substring(0, len));
|
||||||
|
if (count == 0) {
|
||||||
|
return now.format(formatter);
|
||||||
|
}
|
||||||
|
if (unit == 1) {
|
||||||
|
if (suffix == 1) {
|
||||||
|
return now.minusYears(count).format(formatter);
|
||||||
|
}
|
||||||
|
return now.plusYears(count).format(formatter);
|
||||||
|
} else if (unit == 2) {
|
||||||
|
if (suffix == 1) {
|
||||||
|
return now.minusMonths(count).format(formatter);
|
||||||
|
}
|
||||||
|
return now.plusMonths(count).format(formatter);
|
||||||
|
} else {
|
||||||
|
if (suffix == 1) {
|
||||||
|
return now.minusDays(count).format(formatter);
|
||||||
|
}
|
||||||
|
return now.plusDays(count).format(formatter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private String formatValue(List<Map<String, Object>> rows, FilterTreeItem item) {
|
||||||
|
DatasetTableFieldDTO field = item.getField();
|
||||||
|
String dataeaseName = field.getDataeaseName();
|
||||||
|
String value = item.getValue();
|
||||||
|
Float tempFVal = StringUtils.equalsAny(value, "min", "max") ? null : 0f;
|
||||||
|
int validLen = 0;
|
||||||
|
|
||||||
|
for (Map<String, Object> row : rows) {
|
||||||
|
Object o = row.get(dataeaseName);
|
||||||
|
if (ObjectUtils.isEmpty(o)) continue;
|
||||||
|
float fvalue = Float.parseFloat(o.toString());
|
||||||
|
if (StringUtils.equals("min", value)) {
|
||||||
|
if (ObjectUtils.isEmpty(tempFVal)) {
|
||||||
|
tempFVal = fvalue;
|
||||||
|
} else {
|
||||||
|
tempFVal = Math.min(tempFVal, fvalue);
|
||||||
|
}
|
||||||
|
} else if (StringUtils.equals("max", value)) {
|
||||||
|
if (ObjectUtils.isEmpty(tempFVal)) {
|
||||||
|
tempFVal = fvalue;
|
||||||
|
} else {
|
||||||
|
tempFVal = Math.max(tempFVal, fvalue);
|
||||||
|
}
|
||||||
|
} else if (StringUtils.equals("average", value)) {
|
||||||
|
tempFVal += fvalue;
|
||||||
|
validLen++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (StringUtils.equals("average", value)) {
|
||||||
|
return validLen == 0 ? "0f" : String.valueOf((tempFVal / validLen));
|
||||||
|
}
|
||||||
|
return String.valueOf(tempFVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Map<String, Object>> filterRows(List<Map<String, Object>> rows, FilterTreeObj conditionTree, Map<Long, DatasetTableFieldDTO> fieldMap) {
|
||||||
|
chartDynamicMap(rows, conditionTree, fieldMap);
|
||||||
|
List<Map<String, Object>> filteredRows = new ArrayList<>();
|
||||||
|
for (Map<String, Object> row : rows) {
|
||||||
|
if (matchesConditionTree(row, conditionTree, fieldMap)) {
|
||||||
|
filteredRows.add(row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return filteredRows;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean matchesConditionTree(Map<String, Object> row, FilterTreeObj conditionTree, Map<Long, DatasetTableFieldDTO> fieldMap) {
|
||||||
|
if (conditionTree == null || conditionTree.getItems().isEmpty()) {
|
||||||
|
return true; // 如果没有条件树或条件列表为空,返回所有行
|
||||||
|
}
|
||||||
|
List<FilterTreeItem> items = conditionTree.getItems();
|
||||||
|
if (conditionTree.getLogic().equals("or")) {
|
||||||
|
return matchesAnyItem(row, items, fieldMap);
|
||||||
|
}
|
||||||
|
return matchesAllItems(row, items, fieldMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean matchesAllItems(Map<String, Object> row, List<FilterTreeItem> items, Map<Long, DatasetTableFieldDTO> fieldMap) {
|
||||||
|
for (FilterTreeItem item : items) {
|
||||||
|
if (!matchesConditionItem(row, item, fieldMap)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean matchesAnyItem(Map<String, Object> row, List<FilterTreeItem> items, Map<Long, DatasetTableFieldDTO> fieldMap) {
|
||||||
|
for (FilterTreeItem item : items) {
|
||||||
|
if (matchesConditionItem(row, item, fieldMap)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean matchesConditionItem(Map<String, Object> row, FilterTreeItem item, Map<Long, DatasetTableFieldDTO> fieldMap) {
|
||||||
|
if ("item".equals(item.getType())) {
|
||||||
|
DatasetTableFieldDTO fieldDTO = fieldMap.get(item.getFieldId());
|
||||||
|
return rowMatch(row, item, fieldDTO);
|
||||||
|
} else if ("tree".equals(item.getType()) && item.getSubTree() != null) {
|
||||||
|
return matchesConditionTree(row, item.getSubTree(), fieldMap);
|
||||||
|
}
|
||||||
|
return false; // 如果类型不匹配或没有子树,不匹配
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean rowMatch(Map<String, Object> row, FilterTreeItem item, DatasetTableFieldDTO fieldDTO) {
|
||||||
|
String dataeaseName = fieldDTO.getDataeaseName();
|
||||||
|
String filterType = item.getFilterType();
|
||||||
|
Integer deType = fieldDTO.getDeType();
|
||||||
|
Object valueObj = row.get(dataeaseName);
|
||||||
|
if (StringUtils.equals(filterType, "enum")) {
|
||||||
|
List<String> enumValue = item.getEnumValue();
|
||||||
|
return ObjectUtils.isNotEmpty(valueObj) && enumValue.contains(valueObj);
|
||||||
|
} else {
|
||||||
|
String term = item.getTerm();
|
||||||
|
if (Objects.equals(deType, DeTypeConstants.DE_STRING)) {
|
||||||
|
if (valueObj == null) {
|
||||||
|
return StringUtils.equals(term, "null");
|
||||||
|
}
|
||||||
|
if (StringUtils.equals(term, "eq")) {
|
||||||
|
return StringUtils.equals(item.getValue(), valueObj.toString());
|
||||||
|
} else if (StringUtils.equals(term, "not_eq")) {
|
||||||
|
return !StringUtils.equals(item.getValue(), valueObj.toString());
|
||||||
|
} else if (StringUtils.equals(term, "in")) {
|
||||||
|
return Arrays.stream(item.getValue().split(",")).toList().contains(valueObj.toString());
|
||||||
|
} else if (StringUtils.equals(term, "not_in")) {
|
||||||
|
return !Arrays.stream(item.getValue().split(",")).toList().contains(valueObj.toString());
|
||||||
|
} else if (StringUtils.equals(term, "like")) {
|
||||||
|
return StringUtils.contains(item.getValue(), valueObj.toString());
|
||||||
|
} else if (StringUtils.equals(term, "not_like")) {
|
||||||
|
return !StringUtils.contains(item.getValue(), valueObj.toString());
|
||||||
|
} else if (StringUtils.equals(term, "null")) {
|
||||||
|
return false;
|
||||||
|
} else if (StringUtils.equals(term, "not_null")) {
|
||||||
|
return true;
|
||||||
|
} else if (StringUtils.equals(term, "empty")) {
|
||||||
|
return StringUtils.isBlank(valueObj.toString());
|
||||||
|
} else if (StringUtils.equals(term, "not_empty")) {
|
||||||
|
return !StringUtils.isBlank(valueObj.toString());
|
||||||
|
} else {
|
||||||
|
return StringUtils.equals(item.getValue(), valueObj.toString());
|
||||||
|
}
|
||||||
|
} else if (Objects.equals(deType, DeTypeConstants.DE_INT) || Objects.equals(deType, DeTypeConstants.DE_FLOAT)) {
|
||||||
|
if (valueObj == null) return false;
|
||||||
|
if (ObjectUtils.isEmpty(item.getValue())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
float targetVal = Float.parseFloat(item.getValue());
|
||||||
|
float originVal = Float.parseFloat(valueObj.toString());
|
||||||
|
if (StringUtils.equals(term, "eq")) {
|
||||||
|
return StringUtils.equals(String.valueOf(originVal), String.valueOf(targetVal));
|
||||||
|
} else if (StringUtils.equals(term, "not_eq")) {
|
||||||
|
return !StringUtils.equals(String.valueOf(originVal), String.valueOf(targetVal));
|
||||||
|
} else if (StringUtils.equals(term, "gt")) {
|
||||||
|
return targetVal < originVal;
|
||||||
|
} else if (StringUtils.equals(term, "ge")) {
|
||||||
|
return targetVal <= originVal;
|
||||||
|
} else if (StringUtils.equals(term, "lt")) {
|
||||||
|
return targetVal > originVal;
|
||||||
|
} else if (StringUtils.equals(term, "le")) {
|
||||||
|
return targetVal >= originVal;
|
||||||
|
} else {
|
||||||
|
return StringUtils.equals(item.getValue(), valueObj.toString());
|
||||||
|
}
|
||||||
|
} else if (Objects.equals(deType, DeTypeConstants.DE_TIME)) {
|
||||||
|
// 补充时间逻辑
|
||||||
|
return timeMatch(item, valueObj);
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean timeMatch(FilterTreeItem item, Object valueObj) {
|
||||||
|
if (ObjectUtils.isEmpty(valueObj)) return false;
|
||||||
|
String valueText = valueObj.toString();
|
||||||
|
String target = item.getValue();
|
||||||
|
target = target.replaceAll("[^0-9]", "");
|
||||||
|
valueText = valueText.replaceAll("[^0-9]", "");
|
||||||
|
long targetLong = Long.parseLong(target);
|
||||||
|
long valueLong = Long.parseLong(valueText);
|
||||||
|
String term = item.getTerm();
|
||||||
|
if (StringUtils.equals(term, "eq")) {
|
||||||
|
return valueLong == targetLong;
|
||||||
|
} else if (StringUtils.equals(term, "not_eq")) {
|
||||||
|
return valueLong != targetLong;
|
||||||
|
} else if (StringUtils.equals(term, "gt")) {
|
||||||
|
return valueLong > targetLong;
|
||||||
|
} else if (StringUtils.equals(term, "ge")) {
|
||||||
|
return valueLong >= targetLong;
|
||||||
|
} else if (StringUtils.equals(term, "lt")) {
|
||||||
|
return valueLong < targetLong;
|
||||||
|
} else if (StringUtils.equals(term, "le")) {
|
||||||
|
return valueLong <= targetLong;
|
||||||
|
} else {
|
||||||
|
return valueLong == targetLong;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,567 @@
|
|||||||
|
package io.dataease.chart.server;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
|
import io.dataease.api.chart.ChartDataApi;
|
||||||
|
import io.dataease.api.chart.dto.ViewDetailField;
|
||||||
|
import io.dataease.api.chart.request.ChartExcelRequest;
|
||||||
|
import io.dataease.api.chart.request.ChartExcelRequestInner;
|
||||||
|
import io.dataease.auth.DeLinkPermit;
|
||||||
|
import io.dataease.chart.constant.ChartConstants;
|
||||||
|
import io.dataease.chart.manage.ChartDataManage;
|
||||||
|
import io.dataease.constant.AuthConstant;
|
||||||
|
import io.dataease.constant.CommonConstants;
|
||||||
|
import io.dataease.dataset.manage.PermissionManage;
|
||||||
|
import io.dataease.dataset.server.DatasetFieldServer;
|
||||||
|
import io.dataease.constant.DeTypeConstants;
|
||||||
|
import io.dataease.exception.DEException;
|
||||||
|
import io.dataease.exportCenter.manage.ExportCenterManage;
|
||||||
|
import io.dataease.exportCenter.util.ExportCenterUtils;
|
||||||
|
import io.dataease.extensions.datasource.dto.DatasetTableFieldDTO;
|
||||||
|
import io.dataease.extensions.view.dto.*;
|
||||||
|
import io.dataease.license.manage.F2CLicLimitedManage;
|
||||||
|
import io.dataease.result.ResultCode;
|
||||||
|
import io.dataease.utils.JsonUtil;
|
||||||
|
import io.dataease.utils.LogUtil;
|
||||||
|
import io.dataease.visualization.manage.VisualizationTemplateExtendDataManage;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.apache.commons.lang3.ArrayUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||||
|
import org.apache.poi.ss.usermodel.*;
|
||||||
|
import org.apache.poi.ss.util.CellRangeAddress;
|
||||||
|
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import org.springframework.web.context.request.RequestContextHolder;
|
||||||
|
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||||
|
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.text.DecimalFormat;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author Junjun
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/chartData")
|
||||||
|
public class ChartDataServer implements ChartDataApi {
|
||||||
|
@Resource
|
||||||
|
private ChartDataManage chartDataManage;
|
||||||
|
@Resource
|
||||||
|
private ExportCenterManage exportCenterManage;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private VisualizationTemplateExtendDataManage extendDataManage;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private PermissionManage permissionManage;
|
||||||
|
@Resource
|
||||||
|
private DatasetFieldServer datasetFieldServer;
|
||||||
|
|
||||||
|
@Resource(name = "f2CLicLimitedManage")
|
||||||
|
private F2CLicLimitedManage f2CLicLimitedManage;
|
||||||
|
@Value("${dataease.export.page.size:50000}")
|
||||||
|
private Integer extractPageSize;
|
||||||
|
private final Long sheetLimit = 1000000L;
|
||||||
|
|
||||||
|
|
||||||
|
@DeLinkPermit("#p0.sceneId")
|
||||||
|
@Override
|
||||||
|
public ChartViewDTO getData(ChartViewDTO chartViewDTO) throws Exception {
|
||||||
|
try {
|
||||||
|
// 从模板数据获取
|
||||||
|
if (CommonConstants.VIEW_DATA_FROM.TEMPLATE.equalsIgnoreCase(chartViewDTO.getDataFrom())) {
|
||||||
|
return extendDataManage.getChartDataInfo(chartViewDTO.getId(), chartViewDTO);
|
||||||
|
} else {
|
||||||
|
return chartDataManage.calcData(chartViewDTO);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
DEException.throwException(ResultCode.DATA_IS_WRONG.code(), e.getMessage() + "\n\n" + ExceptionUtils.getStackTrace(e));
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ChartViewDTO findExcelData(ChartExcelRequest request) {
|
||||||
|
ChartViewDTO chartViewInfo = new ChartViewDTO();
|
||||||
|
try {
|
||||||
|
ChartViewDTO viewDTO = request.getViewInfo();
|
||||||
|
viewDTO.setIsExcelExport(true);
|
||||||
|
String[] dsHeader = null;
|
||||||
|
Integer[] dsTypes = null;
|
||||||
|
//downloadType = dataset 为下载原始名字 这里做数据转换模拟 table-info类型图表导出
|
||||||
|
if ("dataset".equals(request.getDownloadType())) {
|
||||||
|
viewDTO.setResultMode(ChartConstants.VIEW_RESULT_MODE.ALL);
|
||||||
|
viewDTO.setType("table-info");
|
||||||
|
viewDTO.setRender("antv");
|
||||||
|
List<DatasetTableFieldDTO> sourceFields = datasetFieldServer.listByDatasetGroup(viewDTO.getTableId());
|
||||||
|
List<String> fileNames = permissionManage.filterColumnPermissions(sourceFields, new HashMap<>(), viewDTO.getTableId(), null).stream().map(DatasetTableFieldDTO::getDataeaseName).collect(Collectors.toList());
|
||||||
|
sourceFields = sourceFields.stream().filter(datasetTableFieldDTO -> fileNames.contains(datasetTableFieldDTO.getDataeaseName())).collect(Collectors.toList());
|
||||||
|
dsHeader = sourceFields.stream().map(DatasetTableFieldDTO::getName).toArray(String[]::new);
|
||||||
|
dsTypes = sourceFields.stream().map(DatasetTableFieldDTO::getDeType).toArray(Integer[]::new);
|
||||||
|
TypeReference<List<ChartViewFieldDTO>> listTypeReference = new TypeReference<List<ChartViewFieldDTO>>() {
|
||||||
|
};
|
||||||
|
viewDTO.setXAxis(JsonUtil.parseList(JsonUtil.toJSONString(sourceFields).toString(), listTypeReference));
|
||||||
|
}
|
||||||
|
int curLimit = Math.toIntExact(ExportCenterUtils.getExportLimit("view"));
|
||||||
|
int curDsLimit = Math.toIntExact(ExportCenterUtils.getExportLimit("dataset"));
|
||||||
|
int viewLimit = Math.min(curLimit, curDsLimit);
|
||||||
|
if (ChartConstants.VIEW_RESULT_MODE.CUSTOM.equals(viewDTO.getResultMode())) {
|
||||||
|
Integer limitCount = viewDTO.getResultCount();
|
||||||
|
viewDTO.setResultCount(Math.min(viewLimit, limitCount));
|
||||||
|
} else {
|
||||||
|
viewDTO.setResultCount(viewLimit);
|
||||||
|
}
|
||||||
|
chartViewInfo = getData(viewDTO);
|
||||||
|
List<Object[]> tableRow = (List) chartViewInfo.getData().get("sourceData");
|
||||||
|
if ("dataset".equals(request.getDownloadType())) {
|
||||||
|
request.setHeader(dsHeader);
|
||||||
|
request.setExcelTypes(dsTypes);
|
||||||
|
}
|
||||||
|
request.setDetails(tableRow);
|
||||||
|
request.setData(chartViewInfo.getData());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
return chartViewInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static String valueFormatter(BigDecimal value, FormatterCfgDTO formatter) {
|
||||||
|
if (value == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String result;
|
||||||
|
if (formatter.getType().equals("auto")) {
|
||||||
|
result = transSeparatorAndSuffix(String.valueOf(transUnit(value, formatter)), formatter);
|
||||||
|
} else if (formatter.getType().equals("value")) {
|
||||||
|
result = transSeparatorAndSuffix(transDecimal(transUnit(value, formatter), formatter), formatter);
|
||||||
|
} else if (formatter.getType().equals("percent")) {
|
||||||
|
value = value.multiply(BigDecimal.valueOf(100));
|
||||||
|
result = transSeparatorAndSuffix(transDecimal(value, formatter), formatter);
|
||||||
|
} else {
|
||||||
|
result = value.toString();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BigDecimal transUnit(BigDecimal value, FormatterCfgDTO formatter) {
|
||||||
|
return value.divide(BigDecimal.valueOf(formatter.getUnit()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String transDecimal(BigDecimal value, FormatterCfgDTO formatter) {
|
||||||
|
DecimalFormat df = new DecimalFormat("0." + new String(new char[formatter.getDecimalCount()]).replace('\0', '0'));
|
||||||
|
return df.format(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String transSeparatorAndSuffix(String value, FormatterCfgDTO formatter) {
|
||||||
|
StringBuilder sb = new StringBuilder(value);
|
||||||
|
|
||||||
|
if (formatter.getThousandSeparator()) {
|
||||||
|
Pattern thousandsPattern = Pattern.compile("(\\d)(?=(\\d{3})+$)");
|
||||||
|
String[] numArr = value.split("\\.");
|
||||||
|
numArr[0] = addThousandSeparator(numArr[0], thousandsPattern);
|
||||||
|
sb = new StringBuilder(String.join(".", numArr));
|
||||||
|
}
|
||||||
|
if (formatter.getType().equals("percent")) {
|
||||||
|
sb.append('%');
|
||||||
|
} else {
|
||||||
|
switch (formatter.getUnit()) {
|
||||||
|
case 1000:
|
||||||
|
sb.append("千");
|
||||||
|
break;
|
||||||
|
case 10000:
|
||||||
|
sb.append("万");
|
||||||
|
break;
|
||||||
|
case 1000000:
|
||||||
|
sb.append("百万");
|
||||||
|
break;
|
||||||
|
case 100000000:
|
||||||
|
sb.append('亿');
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String suffix = formatter.getSuffix().trim();
|
||||||
|
if (!suffix.isEmpty()) {
|
||||||
|
if (suffix.equals("%")) {
|
||||||
|
sb.append("\"%\"");
|
||||||
|
} else {
|
||||||
|
sb.append(suffix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static String addThousandSeparator(String numStr, Pattern pattern) {
|
||||||
|
Matcher matcher = pattern.matcher(numStr);
|
||||||
|
StringBuffer sb = new StringBuffer();
|
||||||
|
while (matcher.find()) {
|
||||||
|
matcher.appendReplacement(sb, matcher.group(1) + ",");
|
||||||
|
}
|
||||||
|
matcher.appendTail(sb);
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@DeLinkPermit("#p0.dvId")
|
||||||
|
@Override
|
||||||
|
public void innerExportDetails(ChartExcelRequest request, HttpServletResponse response) throws Exception {
|
||||||
|
HttpServletRequest httpServletRequest = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
|
||||||
|
String linkToken = httpServletRequest.getHeader(AuthConstant.LINK_TOKEN_KEY);
|
||||||
|
LogUtil.info(request.getViewInfo().getId() + " " + StringUtils.isNotEmpty(linkToken) + " " + request.isDataEaseBi());
|
||||||
|
if ((StringUtils.isNotEmpty(linkToken) && !request.isDataEaseBi()) || (request.isDataEaseBi() && StringUtils.isEmpty(linkToken))) {
|
||||||
|
OutputStream outputStream = response.getOutputStream();
|
||||||
|
try {
|
||||||
|
Workbook wb = new SXSSFWorkbook();
|
||||||
|
//给单元格设置样式
|
||||||
|
CellStyle cellStyle = wb.createCellStyle();
|
||||||
|
Font font = wb.createFont();
|
||||||
|
//设置字体大小
|
||||||
|
font.setFontHeightInPoints((short) 12);
|
||||||
|
//设置字体加粗
|
||||||
|
font.setBold(true);
|
||||||
|
//给字体设置样式
|
||||||
|
cellStyle.setFont(font);
|
||||||
|
//设置单元格背景颜色
|
||||||
|
cellStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
|
||||||
|
//设置单元格填充样式(使用纯色背景颜色填充)
|
||||||
|
cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
|
||||||
|
|
||||||
|
if ("dataset".equals(request.getDownloadType()) || request.getViewInfo().getType().equalsIgnoreCase("table-info")) {
|
||||||
|
List<Object[]> details = new ArrayList<>();
|
||||||
|
Sheet detailsSheet;
|
||||||
|
Integer sheetIndex = 1;
|
||||||
|
request.getViewInfo().getChartExtRequest().setPageSize(Long.valueOf(extractPageSize));
|
||||||
|
ChartViewDTO chartViewDTO = findExcelData(request);
|
||||||
|
for (long i = 1; i < chartViewDTO.getTotalPage() + 1; i++) {
|
||||||
|
request.getViewInfo().getChartExtRequest().setGoPage(i);
|
||||||
|
findExcelData(request);
|
||||||
|
details.addAll(request.getDetails());
|
||||||
|
if ((details.size() + extractPageSize) > sheetLimit || i == chartViewDTO.getTotalPage()) {
|
||||||
|
detailsSheet = wb.createSheet("数据" + sheetIndex);
|
||||||
|
Integer[] excelTypes = request.getExcelTypes();
|
||||||
|
details.add(0, request.getHeader());
|
||||||
|
ViewDetailField[] detailFields = request.getDetailFields();
|
||||||
|
Object[] header = request.getHeader();
|
||||||
|
ChartDataServer.setExcelData(detailsSheet, cellStyle, header, details, detailFields, excelTypes, request.getViewInfo(), wb);
|
||||||
|
sheetIndex++;
|
||||||
|
details.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
findExcelData(request);
|
||||||
|
if (CollectionUtils.isEmpty(request.getMultiInfo())) {
|
||||||
|
List<Object[]> details = request.getDetails();
|
||||||
|
Integer[] excelTypes = request.getExcelTypes();
|
||||||
|
details.add(0, request.getHeader());
|
||||||
|
ViewDetailField[] detailFields = request.getDetailFields();
|
||||||
|
Object[] header = request.getHeader();
|
||||||
|
Sheet detailsSheet = wb.createSheet("数据");
|
||||||
|
setExcelData(detailsSheet, cellStyle, header, details, detailFields, excelTypes, request.getViewInfo(), null);
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < request.getMultiInfo().size(); i++) {
|
||||||
|
ChartExcelRequestInner requestInner = request.getMultiInfo().get(i);
|
||||||
|
List<Object[]> details = requestInner.getDetails();
|
||||||
|
Integer[] excelTypes = requestInner.getExcelTypes();
|
||||||
|
details.add(0, requestInner.getHeader());
|
||||||
|
ViewDetailField[] detailFields = requestInner.getDetailFields();
|
||||||
|
Object[] header = requestInner.getHeader();
|
||||||
|
Sheet detailsSheet = wb.createSheet("数据 " + (i + 1));
|
||||||
|
setExcelData(detailsSheet, cellStyle, header, details, detailFields, excelTypes, request.getViewInfo(), null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exportCenterManage.addWatermarkTools(wb);
|
||||||
|
response.setContentType("application/vnd.ms-excel");
|
||||||
|
//文件名称
|
||||||
|
response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(request.getViewName(), StandardCharsets.UTF_8) + ".xlsx");
|
||||||
|
wb.write(outputStream);
|
||||||
|
outputStream.flush();
|
||||||
|
outputStream.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
DEException.throwException(e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
exportCenterManage.addTask(request.getViewId(), "chart", request);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeLinkPermit("#p0.dvId")
|
||||||
|
@Override
|
||||||
|
public void innerExportDataSetDetails(ChartExcelRequest request, HttpServletResponse response) throws Exception {
|
||||||
|
this.innerExportDetails(request, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setExcelData(Sheet detailsSheet, CellStyle cellStyle, Object[] header, List<Object[]> details, ViewDetailField[] detailFields, Integer[] excelTypes, ChartViewDTO viewInfo, Workbook wb) {
|
||||||
|
setExcelData(detailsSheet, cellStyle, header, details, detailFields, excelTypes, null, viewInfo, wb);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void setExcelData(Sheet detailsSheet, CellStyle cellStyle, Object[] header, List<Object[]> details, ViewDetailField[] detailFields, Integer[] excelTypes, Comment comment, ChartViewDTO viewInfo, Workbook wb) {
|
||||||
|
List<CellStyle> styles = new ArrayList<>();
|
||||||
|
List<ChartViewFieldDTO> xAxis = new ArrayList<>();
|
||||||
|
|
||||||
|
xAxis.addAll(viewInfo.getXAxis());
|
||||||
|
xAxis.addAll(viewInfo.getYAxis());
|
||||||
|
xAxis.addAll(viewInfo.getXAxisExt());
|
||||||
|
xAxis.addAll(viewInfo.getYAxisExt());
|
||||||
|
xAxis.addAll(viewInfo.getExtStack());
|
||||||
|
|
||||||
|
if (viewInfo.getType().equalsIgnoreCase("table-normal") || viewInfo.getType().equalsIgnoreCase("table-info")) {
|
||||||
|
for (ChartViewFieldDTO xAxi : xAxis) {
|
||||||
|
if (xAxi.getDeType().equals(DeTypeConstants.DE_INT) || xAxi.getDeType().equals(DeTypeConstants.DE_FLOAT)) {
|
||||||
|
CellStyle formatterCellStyle = createCellStyle(wb, xAxi.getFormatterCfg(), null);
|
||||||
|
styles.add(formatterCellStyle);
|
||||||
|
} else {
|
||||||
|
styles.add(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean mergeHead = false;
|
||||||
|
if (ArrayUtils.isNotEmpty(detailFields)) {
|
||||||
|
cellStyle.setBorderTop(BorderStyle.THIN);
|
||||||
|
cellStyle.setBorderRight(BorderStyle.THIN);
|
||||||
|
cellStyle.setBorderBottom(BorderStyle.THIN);
|
||||||
|
cellStyle.setBorderLeft(BorderStyle.THIN);
|
||||||
|
String[] detailField = Arrays.stream(detailFields).map(ViewDetailField::getName).toList().toArray(new String[detailFields.length]);
|
||||||
|
|
||||||
|
Row row = detailsSheet.createRow(0);
|
||||||
|
int headLen = header.length;
|
||||||
|
int detailFieldLen = detailField.length;
|
||||||
|
for (int i = 0; i < headLen; i++) {
|
||||||
|
Cell cell = row.createCell(i);
|
||||||
|
cell.setCellValue(header[i].toString());
|
||||||
|
if (i < headLen - 1) {
|
||||||
|
CellRangeAddress cellRangeAddress = new CellRangeAddress(0, 1, i, i);
|
||||||
|
detailsSheet.addMergedRegion(cellRangeAddress);
|
||||||
|
} else {
|
||||||
|
for (int j = i + 1; j < detailFieldLen + i; j++) {
|
||||||
|
row.createCell(j).setCellStyle(cellStyle);
|
||||||
|
}
|
||||||
|
CellRangeAddress cellRangeAddress = new CellRangeAddress(0, 0, i, i + detailFieldLen - 1);
|
||||||
|
detailsSheet.addMergedRegion(cellRangeAddress);
|
||||||
|
}
|
||||||
|
cell.setCellStyle(cellStyle);
|
||||||
|
detailsSheet.setColumnWidth(i, 255 * 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
Row detailRow = detailsSheet.createRow(1);
|
||||||
|
for (int i = 0; i < headLen - 1; i++) {
|
||||||
|
Cell cell = detailRow.createCell(i);
|
||||||
|
cell.setCellStyle(cellStyle);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < detailFieldLen; i++) {
|
||||||
|
int colIndex = headLen - 1 + i;
|
||||||
|
Cell cell = detailRow.createCell(colIndex);
|
||||||
|
cell.setCellValue(detailField[i]);
|
||||||
|
cell.setCellStyle(cellStyle);
|
||||||
|
detailsSheet.setColumnWidth(colIndex, 255 * 20);
|
||||||
|
}
|
||||||
|
details.add(1, detailField);
|
||||||
|
mergeHead = true;
|
||||||
|
}
|
||||||
|
if (CollectionUtils.isNotEmpty(details) && (!mergeHead || details.size() > 2)) {
|
||||||
|
int realDetailRowIndex = 2;
|
||||||
|
for (int i = (mergeHead ? 2 : 0); i < details.size(); i++) {
|
||||||
|
Row row = detailsSheet.createRow(realDetailRowIndex > 2 ? realDetailRowIndex : i);
|
||||||
|
Object[] rowData = details.get(i);
|
||||||
|
if (rowData != null) {
|
||||||
|
for (int j = 0; j < rowData.length; j++) {
|
||||||
|
Object cellValObj = rowData[j];
|
||||||
|
if (mergeHead && j == rowData.length - 1 && (cellValObj.getClass().isArray() || cellValObj instanceof ArrayList)) {
|
||||||
|
Object[] detailRowArray = ((List<Object>) cellValObj).toArray(new Object[((List<?>) cellValObj).size()]);
|
||||||
|
int detailRowArrayLen = detailRowArray.length;
|
||||||
|
int temlJ = j;
|
||||||
|
while (detailRowArrayLen > 1 && temlJ-- > 0) {
|
||||||
|
CellRangeAddress cellRangeAddress = new CellRangeAddress(realDetailRowIndex, realDetailRowIndex + detailRowArrayLen - 1, temlJ, temlJ);
|
||||||
|
detailsSheet.addMergedRegion(cellRangeAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int k = 0; k < detailRowArrayLen; k++) {
|
||||||
|
List<Object> detailRows = (List<Object>) detailRowArray[k];
|
||||||
|
Row curRow = row;
|
||||||
|
if (k > 0) {
|
||||||
|
curRow = detailsSheet.createRow(realDetailRowIndex + k);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int l = 0; l < detailRows.size(); l++) {
|
||||||
|
Object col = detailRows.get(l);
|
||||||
|
Cell cell = curRow.createCell(j + l);
|
||||||
|
cell.setCellValue(col.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
realDetailRowIndex += detailRowArrayLen;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Cell cell = row.createCell(j);
|
||||||
|
if (i == 0) {// 头部
|
||||||
|
cell.setCellValue(cellValObj.toString());
|
||||||
|
cell.setCellStyle(cellStyle);
|
||||||
|
//设置列的宽度
|
||||||
|
detailsSheet.setColumnWidth(j, 255 * 20);
|
||||||
|
} else if (cellValObj != null) {
|
||||||
|
try {
|
||||||
|
if ((viewInfo.getType().equalsIgnoreCase("table-normal") || viewInfo.getType().equalsIgnoreCase("table-info")) && (xAxis.get(j).getDeType().equals(DeTypeConstants.DE_INT) || xAxis.get(j).getDeType().equals(DeTypeConstants.DE_FLOAT))) {
|
||||||
|
try {
|
||||||
|
FormatterCfgDTO formatterCfgDTO = xAxis.get(j).getFormatterCfg() == null ? new FormatterCfgDTO() : xAxis.get(j).getFormatterCfg();
|
||||||
|
row.getCell(j).setCellStyle(styles.get(j));
|
||||||
|
row.getCell(j).setCellValue(Double.valueOf(cellValue(formatterCfgDTO, new BigDecimal(cellValObj.toString()))));
|
||||||
|
} catch (Exception e) {
|
||||||
|
cell.setCellValue(cellValObj.toString());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ((excelTypes[j].equals(DeTypeConstants.DE_INT) || excelTypes[j].equals(DeTypeConstants.DE_FLOAT)) && StringUtils.isNotEmpty(cellValObj.toString())) {
|
||||||
|
cell.setCellValue(Double.valueOf(cellValObj.toString()));
|
||||||
|
} else if (cellValObj != null) {
|
||||||
|
cell.setCellValue(cellValObj.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
LogUtil.warn("export excel data transform error");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!viewInfo.getType().equalsIgnoreCase("circle-packing")) {
|
||||||
|
Map<String, Object> senior = viewInfo.getSenior();
|
||||||
|
ChartSeniorFunctionCfgDTO functionCfgDTO = JsonUtil.parseObject((String) JsonUtil.toJSONString(senior.get("functionCfg")), ChartSeniorFunctionCfgDTO.class);
|
||||||
|
if (functionCfgDTO != null && StringUtils.isNotEmpty(functionCfgDTO.getEmptyDataStrategy()) && functionCfgDTO.getEmptyDataStrategy().equalsIgnoreCase("setZero")) {
|
||||||
|
if ((viewInfo.getType().equalsIgnoreCase("table-normal") || viewInfo.getType().equalsIgnoreCase("table-info"))) {
|
||||||
|
if (functionCfgDTO.getEmptyDataFieldCtrl().contains(xAxis.get(j).getDataeaseName())) {
|
||||||
|
cell.setCellValue(0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cell.setCellValue(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String cellValue(FormatterCfgDTO formatterCfgDTO, BigDecimal value) {
|
||||||
|
if (formatterCfgDTO.getType().equalsIgnoreCase("percent")) {
|
||||||
|
return value.toString();
|
||||||
|
} else {
|
||||||
|
return value.divide(BigDecimal.valueOf(formatterCfgDTO.getUnit())).toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static CellStyle createCellStyle(Workbook workbook, FormatterCfgDTO formatter, String value) {
|
||||||
|
CellStyle cellStyle = workbook.createCellStyle();
|
||||||
|
DataFormat format = workbook.createDataFormat();
|
||||||
|
|
||||||
|
if (formatter == null) {
|
||||||
|
cellStyle.setDataFormat(format.getFormat("General"));
|
||||||
|
return cellStyle;
|
||||||
|
}
|
||||||
|
String formatStr = "";
|
||||||
|
if (formatter.getType().equals("auto")) {
|
||||||
|
String[] valueSplit = String.valueOf(value).split(".");
|
||||||
|
if (StringUtils.isEmpty(value) || !value.contains(".")) {
|
||||||
|
formatStr = "0";
|
||||||
|
} else {
|
||||||
|
formatStr = "0." + new String(new char[valueSplit.length]).replace('\0', '0');
|
||||||
|
}
|
||||||
|
switch (formatter.getUnit()) {
|
||||||
|
case 1000:
|
||||||
|
formatStr = formatStr + "千";
|
||||||
|
break;
|
||||||
|
case 10000:
|
||||||
|
formatStr = formatStr + "万";
|
||||||
|
break;
|
||||||
|
case 1000000:
|
||||||
|
formatStr = formatStr + "百万";
|
||||||
|
break;
|
||||||
|
case 100000000:
|
||||||
|
formatStr = formatStr + "'亿'";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (formatter.getThousandSeparator()) {
|
||||||
|
formatStr = "#,##" + formatStr;
|
||||||
|
}
|
||||||
|
if (StringUtils.isNotEmpty(formatter.getSuffix())) {
|
||||||
|
if (formatter.getSuffix().equals("%")) {
|
||||||
|
formatStr = formatStr + "\"%\"";
|
||||||
|
} else {
|
||||||
|
formatStr = formatStr + formatter.getSuffix();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (formatter.getType().equals("value")) {
|
||||||
|
if (formatter.getDecimalCount() > 0) {
|
||||||
|
formatStr = "0." + new String(new char[formatter.getDecimalCount()]).replace('\0', '0');
|
||||||
|
} else {
|
||||||
|
formatStr = "0";
|
||||||
|
}
|
||||||
|
switch (formatter.getUnit()) {
|
||||||
|
case 1000:
|
||||||
|
formatStr = formatStr + "千";
|
||||||
|
break;
|
||||||
|
case 10000:
|
||||||
|
formatStr = formatStr + "万";
|
||||||
|
break;
|
||||||
|
case 1000000:
|
||||||
|
formatStr = formatStr + "百万";
|
||||||
|
break;
|
||||||
|
case 100000000:
|
||||||
|
formatStr = formatStr + "'亿'";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (formatter.getThousandSeparator()) {
|
||||||
|
formatStr = "#,##" + formatStr;
|
||||||
|
}
|
||||||
|
if (StringUtils.isNotEmpty(formatter.getSuffix())) {
|
||||||
|
if (formatter.getSuffix().equals("%")) {
|
||||||
|
formatStr = formatStr + "\"%\"";
|
||||||
|
} else {
|
||||||
|
formatStr = formatStr + formatter.getSuffix();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (formatter.getType().equals("percent")) {
|
||||||
|
if (formatter.getDecimalCount() > 0) {
|
||||||
|
formatStr = "0." + new String(new char[formatter.getDecimalCount()]).replace('\0', '0');
|
||||||
|
} else {
|
||||||
|
formatStr = "0";
|
||||||
|
}
|
||||||
|
formatStr = formatStr + "%";
|
||||||
|
}
|
||||||
|
if (StringUtils.isNotEmpty(formatStr)) {
|
||||||
|
cellStyle.setDataFormat(format.getFormat(formatStr));
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return cellStyle;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getFieldData(ChartViewDTO view, Long fieldId, String fieldType) throws Exception {
|
||||||
|
return chartDataManage.getFieldData(view, fieldId, fieldType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getDrillFieldData(ChartViewDTO view, Long fieldId) throws Exception {
|
||||||
|
return chartDataManage.getDrillFieldData(view, fieldId);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,81 @@
|
|||||||
|
package io.dataease.chart.server;
|
||||||
|
|
||||||
|
import io.dataease.api.chart.ChartViewApi;
|
||||||
|
import io.dataease.api.chart.vo.ChartBaseVO;
|
||||||
|
import io.dataease.extensions.view.dto.ChartViewDTO;
|
||||||
|
import io.dataease.extensions.view.dto.ChartViewFieldDTO;
|
||||||
|
import io.dataease.api.chart.vo.ViewSelectorVO;
|
||||||
|
import io.dataease.chart.manage.ChartViewManege;
|
||||||
|
import io.dataease.exception.DEException;
|
||||||
|
import io.dataease.result.ResultCode;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author Junjun
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("chart")
|
||||||
|
public class ChartViewServer implements ChartViewApi {
|
||||||
|
@Resource
|
||||||
|
private ChartViewManege chartViewManege;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChartViewDTO getData(Long id) throws Exception {
|
||||||
|
try {
|
||||||
|
return chartViewManege.getChart(id);
|
||||||
|
} catch (Exception e) {
|
||||||
|
DEException.throwException(ResultCode.DATA_IS_WRONG.code(), e.getMessage());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, List<ChartViewFieldDTO>> listByDQ(Long id, Long chartId, ChartViewDTO dto) {
|
||||||
|
return chartViewManege.listByDQ(id, chartId, dto);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChartViewDTO save(ChartViewDTO dto) throws Exception {
|
||||||
|
return chartViewManege.save(dto);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String checkSameDataSet(String viewIdSource, String viewIdTarget) {
|
||||||
|
return chartViewManege.checkSameDataSet(viewIdSource, viewIdTarget);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChartViewDTO getDetail(Long id) {
|
||||||
|
return chartViewManege.getDetails(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ViewSelectorVO> viewOption(Long resourceId) {
|
||||||
|
return chartViewManege.viewOption(resourceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void copyField(Long id, Long chartId) {
|
||||||
|
chartViewManege.copyField(id, chartId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteField(Long id) {
|
||||||
|
chartViewManege.deleteField(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteFieldByChart(Long chartId) {
|
||||||
|
chartViewManege.deleteFieldByChartId(chartId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChartBaseVO chartBaseInfo(Long id) {
|
||||||
|
return chartViewManege.chartBaseInfo(id);
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,11 @@
|
|||||||
|
package io.dataease.commons;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class UUIDUtils {
|
||||||
|
|
||||||
|
public static String getUUID() {
|
||||||
|
return UUID.randomUUID().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,75 @@
|
|||||||
|
package io.dataease.commons.constants;
|
||||||
|
|
||||||
|
public class DataVisualizationConstants {
|
||||||
|
|
||||||
|
//新建仪表板来源
|
||||||
|
public static final class QUERY_SOURCE {
|
||||||
|
|
||||||
|
// 定时报告
|
||||||
|
public static final String REPORT = "report";
|
||||||
|
|
||||||
|
// 主工程
|
||||||
|
public static final String MAIN = "main";
|
||||||
|
}
|
||||||
|
|
||||||
|
//新建仪表板来源
|
||||||
|
public static final class NEW_PANEL_FROM {
|
||||||
|
|
||||||
|
// 直接新建
|
||||||
|
public static final String NEW = "new";
|
||||||
|
|
||||||
|
// 内部模板新建
|
||||||
|
public static final String NEW_INNER_TEMPLATE = "new_inner_template";
|
||||||
|
|
||||||
|
// 外部模板新建
|
||||||
|
public static final String NEW_OUTER_TEMPLATE = "new_outer_template";
|
||||||
|
|
||||||
|
// 模板市场新建
|
||||||
|
public static final String NEW_MARKET_TEMPLATE = "new_market_template";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//删除标志
|
||||||
|
public static final class DELETE_FLAG {
|
||||||
|
//已删除
|
||||||
|
public static final boolean DELETED = true;
|
||||||
|
//未删除(可用)
|
||||||
|
public static final boolean AVAILABLE = false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//节点类型
|
||||||
|
public static final class NODE_TYPE {
|
||||||
|
//目录
|
||||||
|
public static final String FOLDER = "folder";
|
||||||
|
//资源节点
|
||||||
|
public static final String LEAF = "leaf";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//操作
|
||||||
|
public static final class RESOURCE_OPT_TYPE {
|
||||||
|
//新建资源节点
|
||||||
|
public static final String NEW_LEAF = "newLeaf";
|
||||||
|
//新建文件夹
|
||||||
|
public static final String NEW_FOLDER = "newFolder";
|
||||||
|
//移动
|
||||||
|
public static final String MOVE = "move";
|
||||||
|
//重命名
|
||||||
|
public static final String RENAME = "rename";
|
||||||
|
|
||||||
|
public static final String EDIT = "edit";
|
||||||
|
//复制
|
||||||
|
public static final String COPY = "copy";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class TEMPLATE_SOURCE {
|
||||||
|
//模板市场
|
||||||
|
public static final String MARKET = "market";
|
||||||
|
//模板管理
|
||||||
|
public static final String MANAGE = "manage";
|
||||||
|
//公共
|
||||||
|
public static final String PUBLIC = "public";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
package io.dataease.commons.constants;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author : WangJiaHao
|
||||||
|
* @date : 2023/10/8 09:37
|
||||||
|
*/
|
||||||
|
public class OptConstants {
|
||||||
|
|
||||||
|
public static final class OPT_TYPE {
|
||||||
|
//新建
|
||||||
|
public static final int NEW = 1;
|
||||||
|
//更新
|
||||||
|
public static final int UPDATE = 2;
|
||||||
|
//删除
|
||||||
|
public static final int DELETE = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class OPT_RESOURCE_TYPE {
|
||||||
|
//可视化资源
|
||||||
|
public static final int VISUALIZATION = 1;
|
||||||
|
//仪表板
|
||||||
|
public static final int DASHBOARD = 2;
|
||||||
|
//数据大屏
|
||||||
|
public static final int DATA_VISUALIZATION = 3;
|
||||||
|
//数据集
|
||||||
|
public static final int DATASET = 4;
|
||||||
|
//数据源
|
||||||
|
public static final int DATASOURCE = 5;
|
||||||
|
//模板
|
||||||
|
public static final int TEMPLATE = 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
package io.dataease.commons.constants;
|
||||||
|
|
||||||
|
public enum TaskStatus {
|
||||||
|
WaitingForExecution, // 等待执行
|
||||||
|
Stopped, // 停止
|
||||||
|
Suspend, // 暂停
|
||||||
|
UnderExecution, // 执行中
|
||||||
|
Completed, //完成
|
||||||
|
Error, //错误
|
||||||
|
|
||||||
|
Warning //警告
|
||||||
|
}
|
@ -0,0 +1,210 @@
|
|||||||
|
package io.dataease.commons.utils;
|
||||||
|
|
||||||
|
import org.apache.commons.codec.binary.Base64;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
import javax.crypto.*;
|
||||||
|
import javax.crypto.spec.IvParameterSpec;
|
||||||
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加密解密工具
|
||||||
|
*
|
||||||
|
* @author kun.mo
|
||||||
|
*/
|
||||||
|
public class CodingUtil {
|
||||||
|
|
||||||
|
private static final String UTF_8 = "UTF-8";
|
||||||
|
|
||||||
|
private static final char[] HEX_DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
|
||||||
|
|
||||||
|
|
||||||
|
public static String[] chars = new String[] { "a", "b", "c", "d", "e", "f",
|
||||||
|
"g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s",
|
||||||
|
"t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5",
|
||||||
|
"6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I",
|
||||||
|
"J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V",
|
||||||
|
"W", "X", "Y", "Z" };
|
||||||
|
/**
|
||||||
|
* MD5加密
|
||||||
|
*
|
||||||
|
* @param src 要加密的串
|
||||||
|
* @return 加密后的字符串
|
||||||
|
*/
|
||||||
|
public static String md5(String src) {
|
||||||
|
return md5(src, UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MD5加密
|
||||||
|
*
|
||||||
|
* @param src 要加密的串
|
||||||
|
* @param charset 加密字符集
|
||||||
|
* @return 加密后的字符串
|
||||||
|
*/
|
||||||
|
public static String md5(String src, String charset) {
|
||||||
|
try {
|
||||||
|
byte[] strTemp = StringUtils.isEmpty(charset) ? src.getBytes() : src.getBytes(charset);
|
||||||
|
MessageDigest mdTemp = MessageDigest.getInstance("MD5");
|
||||||
|
mdTemp.update(strTemp);
|
||||||
|
|
||||||
|
byte[] md = mdTemp.digest();
|
||||||
|
int j = md.length;
|
||||||
|
char[] str = new char[j * 2];
|
||||||
|
int k = 0;
|
||||||
|
|
||||||
|
for (byte byte0 : md) {
|
||||||
|
str[k++] = HEX_DIGITS[byte0 >>> 4 & 0xf];
|
||||||
|
str[k++] = HEX_DIGITS[byte0 & 0xf];
|
||||||
|
}
|
||||||
|
|
||||||
|
return new String(str);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("MD5 encrypt error:", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BASE64解密
|
||||||
|
*
|
||||||
|
* @param src 待解密的字符串
|
||||||
|
* @return 解密后的字符串
|
||||||
|
*/
|
||||||
|
public static String base64Decoding(String src) {
|
||||||
|
byte[] b;
|
||||||
|
String result = null;
|
||||||
|
if (src != null) {
|
||||||
|
try {
|
||||||
|
b = Base64.decodeBase64(src);
|
||||||
|
result = new String(b, UTF_8);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("BASE64 decoding error:", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BASE64加密
|
||||||
|
*
|
||||||
|
* @param src 待加密的字符串
|
||||||
|
* @return 加密后的字符串
|
||||||
|
*/
|
||||||
|
public static String base64Encoding(String src) {
|
||||||
|
String result = null;
|
||||||
|
if (src != null) {
|
||||||
|
try {
|
||||||
|
result = Base64.encodeBase64String(src.getBytes(UTF_8));
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("BASE64 encoding error:", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AES加密
|
||||||
|
*
|
||||||
|
* @param src 待加密字符串
|
||||||
|
* @param secretKey 密钥
|
||||||
|
* @param iv 向量
|
||||||
|
* @return 加密后字符串
|
||||||
|
*/
|
||||||
|
public static String aesEncrypt(String src, String secretKey, String iv) {
|
||||||
|
if (StringUtils.isBlank(secretKey)) {
|
||||||
|
throw new RuntimeException("secretKey is empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
byte[] raw = secretKey.getBytes(UTF_8);
|
||||||
|
SecretKeySpec secretKeySpec = new SecretKeySpec(raw, "AES");
|
||||||
|
// "算法/模式/补码方式" ECB
|
||||||
|
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
|
||||||
|
IvParameterSpec iv1 = new IvParameterSpec(iv.getBytes());
|
||||||
|
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, iv1);
|
||||||
|
byte[] encrypted = cipher.doFinal(src.getBytes(UTF_8));
|
||||||
|
return Base64.encodeBase64String(encrypted);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("AES encrypt error:", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AES 解密
|
||||||
|
*
|
||||||
|
* @param src 待解密字符串
|
||||||
|
* @param secretKey 密钥
|
||||||
|
* @param iv 向量
|
||||||
|
* @return 解密后字符串
|
||||||
|
*/
|
||||||
|
public static String aesDecrypt(String src, String secretKey, String iv) {
|
||||||
|
if (StringUtils.isBlank(secretKey)) {
|
||||||
|
throw new RuntimeException("secretKey is empty");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
byte[] raw = secretKey.getBytes(UTF_8);
|
||||||
|
SecretKeySpec secretKeySpec = new SecretKeySpec(raw, "AES");
|
||||||
|
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
|
||||||
|
IvParameterSpec iv1 = new IvParameterSpec(iv.getBytes());
|
||||||
|
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, iv1);
|
||||||
|
byte[] encrypted1 = Base64.decodeBase64(src);
|
||||||
|
byte[] original = cipher.doFinal(encrypted1);
|
||||||
|
return new String(original, UTF_8);
|
||||||
|
} catch (BadPaddingException | IllegalBlockSizeException e) {
|
||||||
|
// 解密的原字符串为非加密字符串,则直接返回原字符串
|
||||||
|
return src;
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("decrypt error,please check parameters", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static String secretKey() {
|
||||||
|
try {
|
||||||
|
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
|
||||||
|
keyGen.init(128);
|
||||||
|
SecretKey secretKey = keyGen.generateKey();
|
||||||
|
return Base64.encodeBase64String(secretKey.getEncoded());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("generate secretKey error", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isNumeric(String str){
|
||||||
|
for (int i = str.length();--i>=0;){
|
||||||
|
if (!Character.isDigit(str.charAt(i))){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static String shortUuid() {
|
||||||
|
StringBuffer shortBuffer = new StringBuffer();
|
||||||
|
String uuid = UUID.randomUUID().toString().replace("-", "");
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
String str = uuid.substring(i * 4, i * 4 + 4);
|
||||||
|
int x = Integer.parseInt(str, 16);
|
||||||
|
shortBuffer.append(chars[x % 0x3E]);
|
||||||
|
}
|
||||||
|
return shortBuffer.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Integer string2Integer(String str) {
|
||||||
|
StringBuffer sb = new StringBuffer();
|
||||||
|
if (StringUtils.isBlank(str)) return null;
|
||||||
|
for (int i = 0; i < str.length(); i++) {
|
||||||
|
char c = str.charAt(i);
|
||||||
|
if (Character.isDigit(c)) {
|
||||||
|
sb.append(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sb.length() > 0 ? Integer.parseInt(sb.toString()) : null;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
package io.dataease.commons.utils;
|
||||||
|
|
||||||
|
import io.dataease.constant.SortConstants;
|
||||||
|
import io.dataease.visualization.dto.VisualizationNodeBO;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
import java.text.Collator;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author : WangJiaHao
|
||||||
|
* @date : 2024/3/18 10:53
|
||||||
|
*/
|
||||||
|
public class CoreTreeUtils {
|
||||||
|
|
||||||
|
public static List<VisualizationNodeBO> customSortBO(List<VisualizationNodeBO> list, String sortType) {
|
||||||
|
Collator collator = Collator.getInstance(Locale.CHINA);
|
||||||
|
if (StringUtils.equalsIgnoreCase(SortConstants.NAME_DESC, sortType)) {
|
||||||
|
Set<VisualizationNodeBO> poSet = new TreeSet<>(Comparator.comparing(VisualizationNodeBO::getName, collator));
|
||||||
|
poSet.addAll(list);
|
||||||
|
return poSet.stream().collect(Collectors.toList());
|
||||||
|
} else if (StringUtils.equalsIgnoreCase(SortConstants.NAME_ASC, sortType)) {
|
||||||
|
Set<VisualizationNodeBO> poSet = new TreeSet<>(Comparator.comparing(VisualizationNodeBO::getName, collator).reversed());
|
||||||
|
poSet.addAll(list);
|
||||||
|
return poSet.stream().collect(Collectors.toList());
|
||||||
|
} else if (StringUtils.equalsIgnoreCase(SortConstants.TIME_ASC, sortType)) {
|
||||||
|
Collections.reverse(list);
|
||||||
|
return list;
|
||||||
|
} else {
|
||||||
|
// 默认时间倒序
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,98 @@
|
|||||||
|
package io.dataease.commons.utils;
|
||||||
|
|
||||||
|
import io.dataease.utils.LogUtil;
|
||||||
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
|
import org.quartz.CronExpression;
|
||||||
|
import org.quartz.CronScheduleBuilder;
|
||||||
|
import org.quartz.CronTrigger;
|
||||||
|
import org.quartz.TriggerBuilder;
|
||||||
|
|
||||||
|
import java.text.ParseException;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
public class CronUtils {
|
||||||
|
|
||||||
|
|
||||||
|
public static CronTrigger getCronTrigger(String cron) {
|
||||||
|
if (!CronExpression.isValidExpression(cron)) {
|
||||||
|
throw new RuntimeException("cron :" + cron + "表达式解析错误");
|
||||||
|
}
|
||||||
|
return TriggerBuilder.newTrigger().withIdentity("Calculate Date").withSchedule(CronScheduleBuilder.cronSchedule(cron)).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Date getNextTriggerTime(String cron) {
|
||||||
|
Date date = null;
|
||||||
|
try {
|
||||||
|
CronTrigger trigger = getCronTrigger(cron);
|
||||||
|
Date startDate = trigger.getStartTime();
|
||||||
|
date = trigger.getFireTimeAfter(startDate);
|
||||||
|
} catch (Exception e) {
|
||||||
|
LogUtil.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
return date;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String tempCron() {
|
||||||
|
Calendar instance = Calendar.getInstance();
|
||||||
|
instance.add(Calendar.SECOND, 5);
|
||||||
|
return instance.get(Calendar.SECOND) + " " +
|
||||||
|
instance.get(Calendar.MINUTE) + " " +
|
||||||
|
instance.get(Calendar.HOUR_OF_DAY) + " * * ?";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String cron(Integer rateType, String rateVal) {
|
||||||
|
if (rateType == 0) {
|
||||||
|
return rateVal;
|
||||||
|
}
|
||||||
|
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||||
|
|
||||||
|
Date date = null;
|
||||||
|
try {
|
||||||
|
date = sdf.parse(rateVal);
|
||||||
|
} catch (ParseException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
Calendar instance = Calendar.getInstance();
|
||||||
|
assert date != null;
|
||||||
|
instance.setTime(date);
|
||||||
|
|
||||||
|
if (rateType == 1) {
|
||||||
|
return instance.get(Calendar.SECOND) + " " +
|
||||||
|
instance.get(Calendar.MINUTE) + " " +
|
||||||
|
instance.get(Calendar.HOUR_OF_DAY) + " * * ?";
|
||||||
|
}
|
||||||
|
if (rateType == 2) {
|
||||||
|
return instance.get(Calendar.SECOND) + " " +
|
||||||
|
instance.get(Calendar.MINUTE) + " " +
|
||||||
|
instance.get(Calendar.HOUR_OF_DAY) + " ? * " +
|
||||||
|
getDayOfWeek(instance);
|
||||||
|
}
|
||||||
|
if (rateType == 3) {
|
||||||
|
return instance.get(Calendar.SECOND) + " " +
|
||||||
|
instance.get(Calendar.MINUTE) + " " +
|
||||||
|
instance.get(Calendar.HOUR_OF_DAY) + " " +
|
||||||
|
instance.get(Calendar.DATE) + " * ?";
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static String getDayOfWeek(Calendar instance) {
|
||||||
|
int index = instance.get(Calendar.DAY_OF_WEEK);
|
||||||
|
index = (index % 7) + 1;
|
||||||
|
return String.valueOf(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断任务是否过期
|
||||||
|
public static Boolean taskExpire(Long endTime) {
|
||||||
|
if (ObjectUtils.isEmpty(endTime))
|
||||||
|
return false;
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
return now > endTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
package io.dataease.commons.utils;
|
||||||
|
|
||||||
|
import io.dataease.utils.BeanUtils;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class EncryptUtils extends CodingUtil {
|
||||||
|
|
||||||
|
private static final String secretKey = "www.fit2cloud.co";
|
||||||
|
private static final String iv = "1234567890123456";
|
||||||
|
|
||||||
|
|
||||||
|
public static Object aesEncrypt(Object o) {
|
||||||
|
if (o == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return aesEncrypt(o.toString(), secretKey, iv);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Object aesDecrypt(Object o) {
|
||||||
|
if (o == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return aesDecrypt(o.toString(), secretKey, iv);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> Object aesDecrypt(List<T> o, String attrName) {
|
||||||
|
if (o == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return o.stream()
|
||||||
|
.filter(element -> BeanUtils.getFieldValueByName(attrName, element) != null)
|
||||||
|
.peek(element -> BeanUtils.setFieldValueByName(element, attrName, aesDecrypt(BeanUtils.getFieldValueByName(attrName, element).toString(), secretKey, iv), String.class))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Object md5Encrypt(Object o) {
|
||||||
|
if (o == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return md5(o.toString());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,132 @@
|
|||||||
|
package io.dataease.commons.utils;
|
||||||
|
|
||||||
|
import io.dataease.api.permissions.user.vo.UserFormVO;
|
||||||
|
import io.dataease.i18n.Translator;
|
||||||
|
import io.dataease.utils.IPUtils;
|
||||||
|
import io.dataease.visualization.dto.WatermarkContentDTO;
|
||||||
|
import org.apache.poi.ss.usermodel.*;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.awt.Font;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
public class ExcelWatermarkUtils {
|
||||||
|
private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||||
|
|
||||||
|
|
||||||
|
public static String transContent(WatermarkContentDTO watermarkContent, UserFormVO userInfo) {
|
||||||
|
String content = "";
|
||||||
|
switch (watermarkContent.getType()) {
|
||||||
|
case "custom" -> content = watermarkContent.getContent();
|
||||||
|
case "nickName" -> content = "${nickName}";
|
||||||
|
case "ip" -> content = "${ip}";
|
||||||
|
case "time" -> content = "${time}";
|
||||||
|
default -> content = "${username}";
|
||||||
|
}
|
||||||
|
String nickName = userInfo.getName().contains("i18n_") ?Translator.get(userInfo.getName()):userInfo.getName();
|
||||||
|
content = content.replaceAll("\\$\\{ip}", IPUtils.get() == null ? "127.0.0.1" : IPUtils.get());
|
||||||
|
content = content.replaceAll("\\$\\{username}", userInfo.getAccount());
|
||||||
|
content = content.replaceAll("\\$\\{nickName}", nickName);
|
||||||
|
content = content.replaceAll("\\$\\{time}", sdf.format(new Date()));
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加水印图片到工作簿并返回图片 ID
|
||||||
|
*/
|
||||||
|
public static int addWatermarkImage(Workbook wb, WatermarkContentDTO watermarkContent, UserFormVO userInfo) {
|
||||||
|
byte[] imageBytes = createTextImage(transContent(watermarkContent, userInfo), watermarkContent); // 生成文字水印图片
|
||||||
|
return wb.addPicture(imageBytes, Workbook.PICTURE_TYPE_PNG); // 添加到工作簿并返回 ID
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addWatermarkToSheet(Sheet sheet, Integer pictureIdx) {
|
||||||
|
Drawing<?> drawing = sheet.createDrawingPatriarch();
|
||||||
|
CreationHelper helper = sheet.getWorkbook().getCreationHelper();
|
||||||
|
// 获取工作表的总列数和行数
|
||||||
|
int lastRowNum = sheet.getLastRowNum();
|
||||||
|
int totalColumns = 0;
|
||||||
|
for (int i = 0; i <= lastRowNum; i++) {
|
||||||
|
Row row = sheet.getRow(i);
|
||||||
|
if (row != null) {
|
||||||
|
totalColumns = Math.max(totalColumns, row.getLastCellNum());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果没有内容,则假设默认覆盖100行和50列
|
||||||
|
if (lastRowNum == 0 && totalColumns == 0) {
|
||||||
|
lastRowNum = 100;
|
||||||
|
totalColumns = 50;
|
||||||
|
}
|
||||||
|
int picCount = 0;
|
||||||
|
// 根据总行列数循环绘制水印
|
||||||
|
for (int row = 0; row <= lastRowNum; row += 15) { // 每15行绘制一行水印
|
||||||
|
for (int col = 0; col <= totalColumns; col += 8) { // 每8列绘制一列水印
|
||||||
|
// 创建水印图片位置
|
||||||
|
addWater(helper, drawing, picCount++, pictureIdx, col, row, col + 5, row + 10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addWater(CreationHelper helper, Drawing<?> drawing, int picCount, int pictureIdx, int col1, int row1, int col2, int row2) {
|
||||||
|
ClientAnchor anchor = helper.createClientAnchor();
|
||||||
|
// 创建水印图片位置
|
||||||
|
anchor.setCol1(col1); // 水印起始列
|
||||||
|
anchor.setRow1(row1); // 水印起始行
|
||||||
|
anchor.setCol2(col2); // 水印结束列
|
||||||
|
anchor.setRow2(row2); // 水印结束行
|
||||||
|
Picture picture = drawing.createPicture(anchor, pictureIdx);
|
||||||
|
//picture.resize 作用: 因为Excel 显示图片出现bug 使用同一个pictureIdx时如果图片所以参数都一样只是位置不同的时候
|
||||||
|
//会只显示一个 使用picture.resize进行放大倍数的小范围调整可以全部显示
|
||||||
|
picture.resize(1 + (0.000001 * picCount));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] createTextImage(String text, WatermarkContentDTO watermarkContent) {
|
||||||
|
double radians = Math.toRadians(15);// 15度偏转
|
||||||
|
int width = watermarkContent.getWatermark_fontsize() * text.length();
|
||||||
|
int height = (int) Math.round(watermarkContent.getWatermark_fontsize() + width * Math.sin(radians));
|
||||||
|
int fontSize = watermarkContent.getWatermark_fontsize();
|
||||||
|
Color baseColor = Color.decode(watermarkContent.getWatermark_color());
|
||||||
|
|
||||||
|
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
|
||||||
|
Graphics2D g2d = image.createGraphics();
|
||||||
|
|
||||||
|
// 设置透明背景
|
||||||
|
image = g2d.getDeviceConfiguration().createCompatibleImage(width, height, Transparency.TRANSLUCENT);
|
||||||
|
g2d.dispose();
|
||||||
|
g2d = image.createGraphics();
|
||||||
|
|
||||||
|
// 设置抗锯齿
|
||||||
|
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||||
|
|
||||||
|
// 设置字体
|
||||||
|
g2d.setFont(new Font(null, Font.PLAIN, fontSize));
|
||||||
|
g2d.setColor(new Color(baseColor.getRed(), baseColor.getGreen(), baseColor.getBlue(), 50)); // 半透明颜色
|
||||||
|
g2d.rotate(radians, width / 2.0, height / 2.0); // 旋转文字
|
||||||
|
// 绘制文字
|
||||||
|
FontMetrics fontMetrics = g2d.getFontMetrics();
|
||||||
|
int textWidth = fontMetrics.stringWidth(text);
|
||||||
|
int textHeight = fontMetrics.getHeight();
|
||||||
|
int x = (width - textWidth) / 2;
|
||||||
|
int y = (height + textHeight) / 2 - fontMetrics.getDescent();
|
||||||
|
g2d.drawString(text, x, y);
|
||||||
|
|
||||||
|
g2d.dispose();
|
||||||
|
|
||||||
|
// 转为字节数组
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
try {
|
||||||
|
ImageIO.write(image, "png", baos);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return baos.toByteArray();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
package io.dataease.commons.utils;
|
||||||
|
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class MybatisInterceptorConfig {
|
||||||
|
private String modelName;
|
||||||
|
private String attrName;
|
||||||
|
private String attrNameForList;
|
||||||
|
private String interceptorClass;
|
||||||
|
private String interceptorMethod;
|
||||||
|
private String undoClass;
|
||||||
|
private String undoMethod;
|
||||||
|
|
||||||
|
public MybatisInterceptorConfig() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用时需谨慎!!!!!
|
||||||
|
* 主要配置多个的时候,参数少一点
|
||||||
|
*
|
||||||
|
* @param modelClass
|
||||||
|
* @param attrName
|
||||||
|
*/
|
||||||
|
public MybatisInterceptorConfig(Class<?> modelClass, String attrName) {
|
||||||
|
this.modelName = modelClass.getName();
|
||||||
|
this.attrName = attrName;
|
||||||
|
this.interceptorClass = EncryptUtils.class.getName();
|
||||||
|
this.interceptorMethod = "aesEncrypt";
|
||||||
|
this.undoClass = EncryptUtils.class.getName();
|
||||||
|
this.undoMethod = "aesDecrypt";
|
||||||
|
}
|
||||||
|
|
||||||
|
public MybatisInterceptorConfig(Class<?> modelClass, String attrName, Class<?> interceptorClass, String interceptorMethod, String undoMethod) {
|
||||||
|
this.modelName = modelClass.getName();
|
||||||
|
this.attrName = attrName;
|
||||||
|
this.interceptorClass = interceptorClass.getName();
|
||||||
|
this.interceptorMethod = interceptorMethod;
|
||||||
|
this.undoClass = interceptorClass.getName();
|
||||||
|
this.undoMethod = undoMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,759 @@
|
|||||||
|
package io.dataease.commons.utils;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
|
import io.dataease.api.permissions.user.vo.UserFormVO;
|
||||||
|
import io.dataease.api.permissions.variable.dto.SysVariableValueDto;
|
||||||
|
import io.dataease.api.permissions.variable.dto.SysVariableValueItem;
|
||||||
|
import io.dataease.exception.DEException;
|
||||||
|
import io.dataease.extensions.datasource.api.PluginManageApi;
|
||||||
|
import io.dataease.extensions.datasource.dto.DatasourceSchemaDTO;
|
||||||
|
import io.dataease.extensions.datasource.vo.DatasourceConfiguration;
|
||||||
|
import io.dataease.extensions.datasource.vo.XpackPluginsDatasourceVO;
|
||||||
|
import io.dataease.extensions.view.dto.SqlVariableDetails;
|
||||||
|
import io.dataease.i18n.Translator;
|
||||||
|
import io.dataease.license.utils.LicenseUtil;
|
||||||
|
import io.dataease.utils.JsonUtil;
|
||||||
|
import io.dataease.utils.LogUtil;
|
||||||
|
import net.sf.jsqlparser.expression.*;
|
||||||
|
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
|
||||||
|
import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
|
||||||
|
import net.sf.jsqlparser.expression.operators.relational.*;
|
||||||
|
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
|
||||||
|
import net.sf.jsqlparser.statement.Statement;
|
||||||
|
import net.sf.jsqlparser.statement.select.*;
|
||||||
|
import net.sf.jsqlparser.util.deparser.ExpressionDeParser;
|
||||||
|
import net.sf.jsqlparser.util.deparser.SelectDeParser;
|
||||||
|
import org.apache.calcite.sql.*;
|
||||||
|
import org.apache.calcite.sql.parser.SqlParser;
|
||||||
|
import org.apache.calcite.sql.util.SqlShuttle;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
import org.junit.jupiter.params.provider.CsvSource;
|
||||||
|
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import static io.dataease.chart.manage.ChartDataManage.START_END_SEPARATOR;
|
||||||
|
import static org.apache.calcite.sql.SqlKind.*;
|
||||||
|
|
||||||
|
public class SqlparserUtils {
|
||||||
|
public static final String regex = "\\$\\{(.*?)\\}";
|
||||||
|
public static final String regex2 = "\\[(.*?)\\]";
|
||||||
|
private static final String SubstitutedParams = "DATAEASE_PATAMS_BI";
|
||||||
|
private static final String SysParamsSubstitutedParams = "DeSysParams_";
|
||||||
|
private static final String SubstitutedSql = " 'DE-BI' = 'DE-BI' ";
|
||||||
|
private boolean removeSysParams;
|
||||||
|
private UserFormVO userEntity;
|
||||||
|
private final List<Map<String, String>> sysParams = new ArrayList<>();
|
||||||
|
|
||||||
|
public String handleVariableDefaultValue(String sql, String sqlVariableDetails, boolean isEdit, boolean isFromDataSet, List<SqlVariableDetails> parameters, boolean isCross, Map<Long, DatasourceSchemaDTO> dsMap, PluginManageApi pluginManage, UserFormVO userEntity) {
|
||||||
|
DatasourceSchemaDTO ds = dsMap.entrySet().iterator().next().getValue();
|
||||||
|
if (StringUtils.isEmpty(sql)) {
|
||||||
|
DEException.throwException(Translator.get("i18n_sql_not_empty"));
|
||||||
|
}
|
||||||
|
this.userEntity = userEntity;
|
||||||
|
try {
|
||||||
|
this.removeSysParams = true;
|
||||||
|
removeVariables(sql, ds.getType());
|
||||||
|
} catch (Exception e) {
|
||||||
|
DEException.throwException(e);
|
||||||
|
}
|
||||||
|
sql = sql.trim();
|
||||||
|
if (sql.endsWith(";")) {
|
||||||
|
sql = sql.substring(0, sql.length() - 1);
|
||||||
|
}
|
||||||
|
if (StringUtils.isNotEmpty(sqlVariableDetails)) {
|
||||||
|
TypeReference<List<SqlVariableDetails>> listTypeReference = new TypeReference<List<SqlVariableDetails>>() {
|
||||||
|
};
|
||||||
|
List<SqlVariableDetails> defaultsSqlVariableDetails = JsonUtil.parseList(sqlVariableDetails, listTypeReference);
|
||||||
|
Pattern pattern = Pattern.compile(regex);
|
||||||
|
Matcher matcher = pattern.matcher(sql);
|
||||||
|
|
||||||
|
while (matcher.find()) {
|
||||||
|
SqlVariableDetails defaultsSqlVariableDetail = null;
|
||||||
|
for (SqlVariableDetails sqlVariableDetail : defaultsSqlVariableDetails) {
|
||||||
|
if (matcher.group().substring(2, matcher.group().length() - 1).equalsIgnoreCase(sqlVariableDetail.getVariableName())) {
|
||||||
|
defaultsSqlVariableDetail = sqlVariableDetail;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SqlVariableDetails filterParameter = null;
|
||||||
|
if (ObjectUtils.isNotEmpty(parameters)) {
|
||||||
|
for (SqlVariableDetails parameter : parameters) {
|
||||||
|
if (parameter.getVariableName().equalsIgnoreCase(defaultsSqlVariableDetail.getVariableName())) {
|
||||||
|
filterParameter = parameter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (filterParameter != null) {
|
||||||
|
sql = sql.replace(matcher.group(), transFilter(filterParameter, dsMap));
|
||||||
|
} else {
|
||||||
|
if (defaultsSqlVariableDetail != null && StringUtils.isNotEmpty(defaultsSqlVariableDetail.getDefaultValue())) {
|
||||||
|
if (!isEdit && isFromDataSet && defaultsSqlVariableDetail.getDefaultValueScope().equals(SqlVariableDetails.DefaultValueScope.ALLSCOPE)) {
|
||||||
|
sql = sql.replace(matcher.group(), defaultsSqlVariableDetail.getDefaultValue());
|
||||||
|
}
|
||||||
|
if (isEdit) {
|
||||||
|
sql = sql.replace(matcher.group(), defaultsSqlVariableDetail.getDefaultValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.removeSysParams = false;
|
||||||
|
sql = removeVariables(sql, ds.getType());
|
||||||
|
// replace keyword '`'
|
||||||
|
if (!isCross) {
|
||||||
|
Map.Entry<Long, DatasourceSchemaDTO> next = dsMap.entrySet().iterator().next();
|
||||||
|
DatasourceSchemaDTO value = next.getValue();
|
||||||
|
|
||||||
|
String prefix = "";
|
||||||
|
String suffix = "";
|
||||||
|
if (Arrays.stream(DatasourceConfiguration.DatasourceType.values()).map(DatasourceConfiguration.DatasourceType::getType).toList().contains(value.getType())) {
|
||||||
|
DatasourceConfiguration.DatasourceType datasourceType = DatasourceConfiguration.DatasourceType.valueOf(value.getType());
|
||||||
|
prefix = datasourceType.getPrefix();
|
||||||
|
suffix = datasourceType.getSuffix();
|
||||||
|
} else {
|
||||||
|
if (LicenseUtil.licenseValid()) {
|
||||||
|
List<XpackPluginsDatasourceVO> xpackPluginsDatasourceVOS = pluginManage.queryPluginDs();
|
||||||
|
List<XpackPluginsDatasourceVO> list = xpackPluginsDatasourceVOS.stream().filter(ele -> StringUtils.equals(ele.getType(), value.getType())).toList();
|
||||||
|
if (ObjectUtils.isNotEmpty(list)) {
|
||||||
|
XpackPluginsDatasourceVO first = list.getFirst();
|
||||||
|
prefix = first.getPrefix();
|
||||||
|
suffix = first.getSuffix();
|
||||||
|
} else {
|
||||||
|
DEException.throwException("当前数据源插件不存在");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Pattern pattern = Pattern.compile("(`.*?`)");
|
||||||
|
Matcher matcher = pattern.matcher(sql);
|
||||||
|
while (matcher.find()) {
|
||||||
|
String group = matcher.group();
|
||||||
|
String info = group.substring(1, group.length() - 1);
|
||||||
|
sql = sql.replaceAll(group, prefix + info + suffix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.removeSysParams = true;
|
||||||
|
sql = removeVariables(sql, ds.getType());
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return sql;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private String removeVariables(final String sql, String dsType) throws Exception {
|
||||||
|
String tmpSql = sql.replaceAll("(?m)^\\s*$[\n\r]{0,}", "");
|
||||||
|
Pattern pattern = Pattern.compile(regex);
|
||||||
|
Matcher matcher = pattern.matcher(tmpSql);
|
||||||
|
boolean hasVariables = false;
|
||||||
|
while (matcher.find()) {
|
||||||
|
hasVariables = true;
|
||||||
|
tmpSql = tmpSql.replace(matcher.group(), SubstitutedParams);
|
||||||
|
}
|
||||||
|
if (removeSysParams) {
|
||||||
|
for (Map<String, String> sysParam : sysParams) {
|
||||||
|
tmpSql = tmpSql.replaceAll(sysParam.get("replace"), sysParam.get("origin"));
|
||||||
|
}
|
||||||
|
pattern = Pattern.compile(regex2);
|
||||||
|
matcher = pattern.matcher(tmpSql);
|
||||||
|
while (matcher.find()) {
|
||||||
|
hasVariables = true;
|
||||||
|
tmpSql = tmpSql.replace(matcher.group(), SubstitutedParams);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pattern = Pattern.compile(regex2);
|
||||||
|
matcher = pattern.matcher(tmpSql);
|
||||||
|
sysParams.clear();
|
||||||
|
while (matcher.find()) {
|
||||||
|
hasVariables = true;
|
||||||
|
tmpSql = tmpSql.replace(matcher.group(), SysParamsSubstitutedParams + matcher.group().substring(1, matcher.group().length() - 1));
|
||||||
|
Map<String, String> sysParam = new HashMap<>();
|
||||||
|
sysParam.put("origin", matcher.group());
|
||||||
|
sysParam.put("replace", SysParamsSubstitutedParams + matcher.group().substring(1, matcher.group().length() - 1));
|
||||||
|
sysParams.add(sysParam);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!hasVariables && !sql.contains(SubstitutedParams)){
|
||||||
|
return sql;
|
||||||
|
}
|
||||||
|
Statement statement = CCJSqlParserUtil.parse(tmpSql);
|
||||||
|
Select select = (Select) statement;
|
||||||
|
if (CollectionUtils.isNotEmpty(select.getWithItemsList())) {
|
||||||
|
for (Iterator<WithItem> iter = select.getWithItemsList().iterator(); iter.hasNext(); ) {
|
||||||
|
WithItem withItem = iter.next();
|
||||||
|
ParenthesedSelect parenthesedSelect = (ParenthesedSelect) withItem.getSelect();
|
||||||
|
parenthesedSelect.setSelect((Select) CCJSqlParserUtil.parse(removeVariables(parenthesedSelect.getSelect().toString(), dsType)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (select.getSelectBody() instanceof PlainSelect) {
|
||||||
|
return handlePlainSelect((PlainSelect) select.getSelectBody(), select, dsType);
|
||||||
|
} else {
|
||||||
|
StringBuilder result = new StringBuilder();
|
||||||
|
SetOperationList setOperationList = (SetOperationList) select.getSelectBody();
|
||||||
|
for (int i = 0; i < setOperationList.getSelects().size(); i++) {
|
||||||
|
result.append(handlePlainSelect((PlainSelect) setOperationList.getSelects().get(i), null, dsType));
|
||||||
|
if (i < setOperationList.getSelects().size() - 1) {
|
||||||
|
result.append(" ").append(setOperationList.getOperations().get(i).toString()).append(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return select.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String handlePlainSelect(PlainSelect plainSelect, Select statementSelect, String dsType) throws Exception {
|
||||||
|
handleSelectItems(plainSelect, dsType);
|
||||||
|
handleFromItems(plainSelect, dsType);
|
||||||
|
handleJoins(plainSelect, dsType);
|
||||||
|
handleHaving(plainSelect);
|
||||||
|
return handleWhere(plainSelect, statementSelect, dsType);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleSelectItems(PlainSelect plainSelect, String dsType) throws Exception {
|
||||||
|
List<SelectItem<?>> selectItems = new ArrayList<>();
|
||||||
|
for (SelectItem selectItem : plainSelect.getSelectItems()) {
|
||||||
|
try {
|
||||||
|
if (selectItem.getExpression() instanceof ParenthesedSelect) {
|
||||||
|
ParenthesedSelect parenthesedSelect = (ParenthesedSelect) selectItem.getExpression();
|
||||||
|
parenthesedSelect.setSelect((Select) CCJSqlParserUtil.parse(removeVariables(((Select) selectItem.getExpression()).getPlainSelect().toString(), dsType)));
|
||||||
|
selectItem.setExpression(parenthesedSelect);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
selectItems.add(selectItem);
|
||||||
|
}
|
||||||
|
plainSelect.setSelectItems(selectItems);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleFromItems(PlainSelect plainSelect, String dsType) throws Exception {
|
||||||
|
FromItem fromItem = plainSelect.getFromItem();
|
||||||
|
if (fromItem instanceof ParenthesedSelect) {
|
||||||
|
handleParenthesedSelect(fromItem, dsType);
|
||||||
|
plainSelect.setFromItem(fromItem);
|
||||||
|
} else {
|
||||||
|
if (fromItem instanceof ParenthesedFromItem) {
|
||||||
|
fromItem = ((ParenthesedFromItem) fromItem).getFromItem();
|
||||||
|
while (fromItem instanceof ParenthesedFromItem) {
|
||||||
|
fromItem = ((ParenthesedFromItem) fromItem).getFromItem();
|
||||||
|
}
|
||||||
|
handleParenthesedSelect(fromItem, dsType);
|
||||||
|
}
|
||||||
|
plainSelect.setFromItem(fromItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleParenthesedSelect(FromItem fromItem, String dsType) throws Exception {
|
||||||
|
if (((ParenthesedSelect) fromItem).getSelect() instanceof SetOperationList) {
|
||||||
|
StringBuilder result = new StringBuilder();
|
||||||
|
SetOperationList setOperationList = (SetOperationList) ((ParenthesedSelect) fromItem).getSelect().getSelectBody();
|
||||||
|
for (int i = 0; i < setOperationList.getSelects().size(); i++) {
|
||||||
|
result.append(handlePlainSelect((PlainSelect) setOperationList.getSelects().get(i), null, dsType));
|
||||||
|
if (i < setOperationList.getSelects().size() - 1) {
|
||||||
|
result.append(" ").append(setOperationList.getOperations().get(i).toString()).append(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
PlainSelect selectBody = ((ParenthesedSelect) fromItem).getSelect().getPlainSelect();
|
||||||
|
Select subSelectTmp = (Select) CCJSqlParserUtil.parse(removeVariables(selectBody.toString(), dsType));
|
||||||
|
((ParenthesedSelect) fromItem).setSelect(subSelectTmp.getSelectBody());
|
||||||
|
if (dsType.equals(DatasourceConfiguration.DatasourceType.oracle.getType())) {
|
||||||
|
if (fromItem.getAlias() != null) {
|
||||||
|
fromItem.setAlias(new Alias(fromItem.getAlias().toString(), false));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (fromItem.getAlias() == null) {
|
||||||
|
throw new Exception("Failed to parse sql, Every derived table must have its own alias!");
|
||||||
|
}
|
||||||
|
fromItem.setAlias(new Alias(fromItem.getAlias().toString(), false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleJoins(PlainSelect plainSelect, String dsType) throws Exception {
|
||||||
|
List<Join> joins = plainSelect.getJoins();
|
||||||
|
if (joins != null) {
|
||||||
|
List<Join> joinsList = new ArrayList<>();
|
||||||
|
for (Join join : joins) {
|
||||||
|
FromItem rightItem = join.getRightItem();
|
||||||
|
Collection<Expression> exprs = join.getOnExpressions();
|
||||||
|
Collection<Expression> exprs2 = new ArrayList<>();
|
||||||
|
for (Expression expr : exprs) {
|
||||||
|
StringBuilder stringBuilder = new StringBuilder();
|
||||||
|
BinaryExpression binaryExpression = null;
|
||||||
|
try {
|
||||||
|
binaryExpression = (BinaryExpression) expr;
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
if (binaryExpression != null) {
|
||||||
|
boolean hasSubBinaryExpression = binaryExpression instanceof AndExpression || binaryExpression instanceof OrExpression;
|
||||||
|
if (!hasSubBinaryExpression && !(binaryExpression.getLeftExpression() instanceof BinaryExpression) && !(binaryExpression.getLeftExpression() instanceof InExpression) && (hasVariable(binaryExpression.getLeftExpression().toString()) || hasVariable(binaryExpression.getRightExpression().toString()))) {
|
||||||
|
stringBuilder.append(handleSubstitutedSql(binaryExpression.toString()));
|
||||||
|
} else {
|
||||||
|
expr.accept(getExpressionDeParser(stringBuilder));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
expr.accept(getExpressionDeParser(stringBuilder));
|
||||||
|
}
|
||||||
|
exprs2.add(CCJSqlParserUtil.parseCondExpression(stringBuilder.toString()));
|
||||||
|
}
|
||||||
|
join.setOnExpressions(exprs2);
|
||||||
|
if (rightItem instanceof ParenthesedSelect) {
|
||||||
|
try {
|
||||||
|
PlainSelect selectBody = ((ParenthesedSelect) rightItem).getPlainSelect();
|
||||||
|
Select subSelectTmp = (Select) CCJSqlParserUtil.parse(removeVariables(selectBody.toString(), dsType));
|
||||||
|
PlainSelect subPlainSelect = ((PlainSelect) subSelectTmp.getSelectBody());
|
||||||
|
((ParenthesedSelect) rightItem).setSelect(subPlainSelect);
|
||||||
|
} catch (Exception e) {
|
||||||
|
SetOperationList select = ((ParenthesedSelect) rightItem).getSetOperationList();
|
||||||
|
SetOperationList setOperationList = new SetOperationList();
|
||||||
|
setOperationList.setSelects(new ArrayList<>());
|
||||||
|
setOperationList.setOperations(select.getOperations());
|
||||||
|
for (Select selectSelect : select.getSelects()) {
|
||||||
|
Select subSelectTmp = (Select) CCJSqlParserUtil.parse(removeVariables(selectSelect.toString(), dsType));
|
||||||
|
setOperationList.getSelects().add(subSelectTmp);
|
||||||
|
}
|
||||||
|
((ParenthesedSelect) rightItem).setSelect(setOperationList);
|
||||||
|
}
|
||||||
|
if (dsType.equals(DatasourceConfiguration.DatasourceType.oracle.getType())) {
|
||||||
|
rightItem.setAlias(new Alias(rightItem.getAlias().toString(), false));
|
||||||
|
} else {
|
||||||
|
if (rightItem.getAlias() == null) {
|
||||||
|
throw new Exception("Failed to parse sql, Every derived table must have its own alias!");
|
||||||
|
}
|
||||||
|
rightItem.setAlias(new Alias(rightItem.getAlias().toString(), false));
|
||||||
|
}
|
||||||
|
join.setRightItem(rightItem);
|
||||||
|
}
|
||||||
|
joinsList.add(join);
|
||||||
|
}
|
||||||
|
plainSelect.setJoins(joinsList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleHaving(PlainSelect plainSelect) throws Exception {
|
||||||
|
Expression expr = plainSelect.getHaving();
|
||||||
|
if (expr == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
StringBuilder stringBuilder = new StringBuilder();
|
||||||
|
BinaryExpression binaryExpression = null;
|
||||||
|
try {
|
||||||
|
binaryExpression = (BinaryExpression) expr;
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
if (binaryExpression != null) {
|
||||||
|
boolean hasSubBinaryExpression = binaryExpression instanceof AndExpression || binaryExpression instanceof OrExpression;
|
||||||
|
if (!hasSubBinaryExpression && !(binaryExpression.getLeftExpression() instanceof BinaryExpression) && !(binaryExpression.getLeftExpression() instanceof InExpression) && (hasVariable(binaryExpression.getLeftExpression().toString()) || hasVariable(binaryExpression.getRightExpression().toString()))) {
|
||||||
|
stringBuilder.append(handleSubstitutedSql(binaryExpression.toString()));
|
||||||
|
} else {
|
||||||
|
expr.accept(getExpressionDeParser(stringBuilder));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
expr.accept(getExpressionDeParser(stringBuilder));
|
||||||
|
}
|
||||||
|
plainSelect.setHaving(CCJSqlParserUtil.parseCondExpression(stringBuilder.toString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String handleWhere(PlainSelect plainSelect, Select statementSelect, String dsType) throws Exception {
|
||||||
|
Expression expr = plainSelect.getWhere();
|
||||||
|
if (expr == null) {
|
||||||
|
return handleWith(plainSelect, statementSelect, dsType);
|
||||||
|
}
|
||||||
|
StringBuilder stringBuilder = new StringBuilder();
|
||||||
|
BinaryExpression binaryExpression = null;
|
||||||
|
try {
|
||||||
|
binaryExpression = (BinaryExpression) expr;
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
if (binaryExpression != null) {
|
||||||
|
boolean hasSubBinaryExpression = binaryExpression instanceof AndExpression || binaryExpression instanceof OrExpression;
|
||||||
|
if (!hasSubBinaryExpression && !(binaryExpression.getLeftExpression() instanceof BinaryExpression) && !(binaryExpression.getLeftExpression() instanceof InExpression) && (hasVariable(binaryExpression.getLeftExpression().toString()) || hasVariable(binaryExpression.getRightExpression().toString()))) {
|
||||||
|
stringBuilder.append(handleSubstitutedSql(binaryExpression.toString()));
|
||||||
|
} else {
|
||||||
|
expr.accept(getExpressionDeParser(stringBuilder));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
expr.accept(getExpressionDeParser(stringBuilder));
|
||||||
|
}
|
||||||
|
plainSelect.setWhere(CCJSqlParserUtil.parseCondExpression(stringBuilder.toString()));
|
||||||
|
return handleWith(plainSelect, statementSelect, dsType);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String handleWith(PlainSelect plainSelect, Select select, String dsType) throws Exception {
|
||||||
|
if (select != null && CollectionUtils.isNotEmpty(select.getWithItemsList())) {
|
||||||
|
for (Iterator<WithItem> iter = select.getWithItemsList().iterator(); iter.hasNext(); ) {
|
||||||
|
WithItem withItem = iter.next();
|
||||||
|
ParenthesedSelect parenthesedSelect = (ParenthesedSelect) withItem.getSelect();
|
||||||
|
parenthesedSelect.setSelect((Select) CCJSqlParserUtil.parse(removeVariables(parenthesedSelect.getSelect().toString(), dsType)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return plainSelect.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ExpressionDeParser getExpressionDeParser(StringBuilder stringBuilder) {
|
||||||
|
ExpressionDeParser expressionDeParser = new ExpressionDeParser(null, stringBuilder) {
|
||||||
|
@Override
|
||||||
|
public void visit(Parenthesis parenthesis) {
|
||||||
|
getBuffer().append("(");
|
||||||
|
parenthesis.getExpression().accept(this);
|
||||||
|
getBuffer().append(")");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(OrExpression orExpression) {
|
||||||
|
visitBinaryExpr(orExpression, "OR");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(AndExpression andExpression) {
|
||||||
|
visitBinaryExpr(andExpression, andExpression.isUseOperator() ? " && " : " AND ");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(Between between) {
|
||||||
|
if (hasVariable(between.getBetweenExpressionStart().toString()) || hasVariable(between.getBetweenExpressionEnd().toString())) {
|
||||||
|
getBuffer().append(handleSubstitutedSql(between.toString()));
|
||||||
|
} else {
|
||||||
|
getBuffer().append(between.getLeftExpression()).append(" BETWEEN ").append(between.getBetweenExpressionStart()).append(" AND ").append(between.getBetweenExpressionEnd());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(MinorThan minorThan) {
|
||||||
|
if (hasVariable(minorThan.getLeftExpression().toString()) || hasVariable(minorThan.getRightExpression().toString())) {
|
||||||
|
getBuffer().append(handleSubstitutedSql(minorThan.toString()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
getBuffer().append(minorThan.getLeftExpression());
|
||||||
|
getBuffer().append(" < ");
|
||||||
|
getBuffer().append(minorThan.getRightExpression());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(MinorThanEquals minorThan) {
|
||||||
|
if (hasVariable(minorThan.getLeftExpression().toString()) || hasVariable(minorThan.getRightExpression().toString())) {
|
||||||
|
getBuffer().append(handleSubstitutedSql(minorThan.toString()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
getBuffer().append(minorThan.getLeftExpression());
|
||||||
|
getBuffer().append(" <= ");
|
||||||
|
getBuffer().append(minorThan.getRightExpression());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(GreaterThanEquals minorThan) {
|
||||||
|
if (hasVariable(minorThan.getLeftExpression().toString()) || hasVariable(minorThan.getRightExpression().toString())) {
|
||||||
|
getBuffer().append(handleSubstitutedSql(minorThan.toString()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
getBuffer().append(minorThan.getLeftExpression());
|
||||||
|
getBuffer().append(" >= ");
|
||||||
|
getBuffer().append(minorThan.getRightExpression());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(GreaterThan greaterThan) {
|
||||||
|
if (hasVariable(greaterThan.getLeftExpression().toString()) || hasVariable(greaterThan.getRightExpression().toString())) {
|
||||||
|
getBuffer().append(handleSubstitutedSql(greaterThan.toString()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
getBuffer().append(greaterThan.getLeftExpression());
|
||||||
|
getBuffer().append(" > ");
|
||||||
|
getBuffer().append(greaterThan.getRightExpression());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(ExpressionList expressionList) {
|
||||||
|
for (Iterator<Expression> iter = expressionList.getExpressions().iterator(); iter.hasNext(); ) {
|
||||||
|
Expression expression = iter.next();
|
||||||
|
expression.accept(this);
|
||||||
|
if (iter.hasNext()) {
|
||||||
|
buffer.append(", ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(LikeExpression likeExpression) {
|
||||||
|
if (hasVariable(likeExpression.toString())) {
|
||||||
|
getBuffer().append(handleSubstitutedSql(likeExpression.toString()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
visitBinaryExpression(likeExpression, (likeExpression.isNot() ? " NOT" : "") + (likeExpression.isCaseInsensitive() ? " ILIKE " : " LIKE "));
|
||||||
|
if (likeExpression.getEscape() != null) {
|
||||||
|
buffer.append(" ESCAPE '").append(likeExpression.getEscape()).append('\'');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(InExpression inExpression) {
|
||||||
|
if (inExpression.getRightExpression() != null && hasVariable(inExpression.getRightExpression().toString()) && !(inExpression.getRightExpression() instanceof ParenthesedSelect)) {
|
||||||
|
stringBuilder.append(handleSubstitutedSqlForIn(inExpression.toString()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
inExpression.getLeftExpression().accept(this);
|
||||||
|
if (inExpression.isNot()) {
|
||||||
|
getBuffer().append(" " + " NOT IN " + " ");
|
||||||
|
} else {
|
||||||
|
getBuffer().append(" IN ");
|
||||||
|
}
|
||||||
|
if (inExpression.getRightExpression() != null && inExpression.getRightExpression() instanceof ParenthesedSelect) {
|
||||||
|
try {
|
||||||
|
ParenthesedSelect subSelect = (ParenthesedSelect) inExpression.getRightExpression();
|
||||||
|
Select select = (Select) CCJSqlParserUtil.parse(removeVariables(subSelect.getPlainSelect().toString(), ""));
|
||||||
|
subSelect.setSelect(select);
|
||||||
|
inExpression.setRightExpression(subSelect);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
inExpression.getRightExpression().accept(this);
|
||||||
|
}
|
||||||
|
if (inExpression.getRightExpression() instanceof ParenthesedExpressionList) {
|
||||||
|
buffer.append(inExpression.getRightExpression());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(ParenthesedSelect subSelect) {
|
||||||
|
StringBuilder stringBuilder = new StringBuilder();
|
||||||
|
Expression in = ((PlainSelect) subSelect.getSelectBody()).getWhere();
|
||||||
|
if (in instanceof BinaryExpression && hasVariable(in.toString())) {
|
||||||
|
stringBuilder.append(SubstitutedParams);
|
||||||
|
} else {
|
||||||
|
in.accept(getExpressionDeParser(stringBuilder));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Expression where = CCJSqlParserUtil.parseCondExpression(stringBuilder.toString());
|
||||||
|
((PlainSelect) subSelect.getSelectBody()).setWhere(where);
|
||||||
|
getBuffer().append(subSelect.getSelectBody());
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(Select selectBody) {
|
||||||
|
getBuffer().append(selectBody.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void visitBinaryExpr(BinaryExpression expr, String operator) {
|
||||||
|
boolean hasSubBinaryExpression = false;
|
||||||
|
if (expr.getLeftExpression() instanceof Parenthesis) {
|
||||||
|
try {
|
||||||
|
Parenthesis parenthesis = (Parenthesis) expr.getLeftExpression();
|
||||||
|
BinaryExpression leftBinaryExpression = (BinaryExpression) parenthesis.getExpression();
|
||||||
|
hasSubBinaryExpression = leftBinaryExpression instanceof AndExpression || leftBinaryExpression instanceof OrExpression;
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (expr.getLeftExpression() instanceof BinaryExpression) {
|
||||||
|
try {
|
||||||
|
BinaryExpression leftBinaryExpression = (BinaryExpression) expr.getLeftExpression();
|
||||||
|
hasSubBinaryExpression = leftBinaryExpression instanceof AndExpression || leftBinaryExpression instanceof OrExpression;
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((expr.getLeftExpression() instanceof BinaryExpression || expr.getLeftExpression() instanceof Parenthesis) && !hasSubBinaryExpression && hasVariable(expr.getLeftExpression().toString())) {
|
||||||
|
getBuffer().append(handleSubstitutedSql(expr.getLeftExpression().toString()));
|
||||||
|
} else {
|
||||||
|
expr.getLeftExpression().accept(this);
|
||||||
|
}
|
||||||
|
getBuffer().append(" " + operator + " ");
|
||||||
|
hasSubBinaryExpression = false;
|
||||||
|
if (expr.getRightExpression() instanceof Parenthesis) {
|
||||||
|
try {
|
||||||
|
Parenthesis parenthesis = (Parenthesis) expr.getRightExpression();
|
||||||
|
BinaryExpression rightBinaryExpression = (BinaryExpression) parenthesis.getExpression();
|
||||||
|
hasSubBinaryExpression = rightBinaryExpression instanceof AndExpression || rightBinaryExpression instanceof OrExpression;
|
||||||
|
} catch (Exception e) {
|
||||||
|
LogUtil.error("Failed parse sql", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (expr.getRightExpression() instanceof BinaryExpression) {
|
||||||
|
try {
|
||||||
|
BinaryExpression rightBinaryExpression = (BinaryExpression) expr.getRightExpression();
|
||||||
|
hasSubBinaryExpression = rightBinaryExpression instanceof AndExpression || rightBinaryExpression instanceof OrExpression;
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((expr.getRightExpression() instanceof Parenthesis || expr.getRightExpression() instanceof BinaryExpression || expr.getRightExpression() instanceof Function) && !hasSubBinaryExpression && hasVariable(expr.getRightExpression().toString())) {
|
||||||
|
getBuffer().append(handleSubstitutedSql(expr.getRightExpression().toString()));
|
||||||
|
} else {
|
||||||
|
expr.getRightExpression().accept(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return expressionDeParser;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasVariable(String sql) {
|
||||||
|
return sql.contains(SubstitutedParams) || (!removeSysParams && sql.contains(SysParamsSubstitutedParams));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void getDependencies(SqlNode sqlNode, Boolean fromOrJoin) {
|
||||||
|
if (sqlNode == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (sqlNode.getKind() == JOIN) {
|
||||||
|
SqlJoin sqlKind = (SqlJoin) sqlNode;
|
||||||
|
|
||||||
|
} else if (sqlNode.getKind() == IDENTIFIER) {
|
||||||
|
} else if (sqlNode.getKind() == AS) {
|
||||||
|
SqlBasicCall sqlKind = (SqlBasicCall) sqlNode;
|
||||||
|
} else if (sqlNode.getKind() == SELECT) {
|
||||||
|
SqlSelect sqlKind = (SqlSelect) sqlNode;
|
||||||
|
List<SqlNode> list = sqlKind.getSelectList().getList();
|
||||||
|
for (SqlNode i : list) {
|
||||||
|
getDependencies(i, false);
|
||||||
|
}
|
||||||
|
SqlNode from = sqlKind.getFrom().accept(getSqlShuttle());
|
||||||
|
sqlKind.setFrom(from);
|
||||||
|
if (sqlKind.getWhere() != null) {
|
||||||
|
SqlNode newWhere = sqlKind.getWhere().accept(getSqlShuttle());
|
||||||
|
sqlKind.setWhere(newWhere);
|
||||||
|
}
|
||||||
|
} else if (sqlNode.getKind() == ORDER_BY) {
|
||||||
|
SqlOrderBy sqlKind = (SqlOrderBy) sqlNode;
|
||||||
|
List<SqlNode> operandList = sqlKind.getOperandList();
|
||||||
|
for (int i = 0; i < operandList.size(); i++) {
|
||||||
|
getDependencies(operandList.get(i), false);
|
||||||
|
}
|
||||||
|
} else if (sqlNode.getKind() == UNION) {
|
||||||
|
SqlBasicCall sqlKind = (SqlBasicCall) sqlNode;
|
||||||
|
if (sqlKind.getOperandList().size() >= 2) {
|
||||||
|
for (int i = 0; i < sqlKind.getOperandList().size(); i++) {
|
||||||
|
getDependencies(sqlKind.getOperandList().get(i), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private SqlShuttle getSqlShuttle() {
|
||||||
|
return new SqlShuttle() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable SqlNode visit(final SqlCall call) {
|
||||||
|
CallCopyingArgHandler argHandler = new CallCopyingArgHandler(call, false);
|
||||||
|
call.getOperator().acceptCall(this, call, false, argHandler);
|
||||||
|
if (argHandler.result().toString().contains(SubstitutedParams)) {
|
||||||
|
SqlNode sqlNode1 = null;
|
||||||
|
try {
|
||||||
|
sqlNode1 = SqlParser.create(SubstitutedSql).parseExpression();
|
||||||
|
} catch (Exception e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
return sqlNode1;
|
||||||
|
}
|
||||||
|
return argHandler.result();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private String transFilter(SqlVariableDetails sqlVariableDetails, Map<Long, DatasourceSchemaDTO> dsMap) {
|
||||||
|
if (sqlVariableDetails.getOperator().equals("in")) {
|
||||||
|
if (StringUtils.equalsIgnoreCase(dsMap.entrySet().iterator().next().getValue().getType(), DatasourceConfiguration.DatasourceType.sqlServer.getType())
|
||||||
|
&& sqlVariableDetails.getDeType() == 0) {
|
||||||
|
return "N'" + String.join("', N'", sqlVariableDetails.getValue()) + "'";
|
||||||
|
} else {
|
||||||
|
if (sqlVariableDetails.getDeType() == 2 || sqlVariableDetails.getDeType() == 3) {
|
||||||
|
return String.join(",", sqlVariableDetails.getValue());
|
||||||
|
} else {
|
||||||
|
return "'" + String.join("','", sqlVariableDetails.getValue()) + "'";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (sqlVariableDetails.getOperator().equals("between")) {
|
||||||
|
if (sqlVariableDetails.getDeType() == 1) {
|
||||||
|
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(sqlVariableDetails.getType().size() > 1 ? (String) sqlVariableDetails.getType().get(1).replace("DD", "dd").replace("YYYY", "yyyy") : "yyyy");
|
||||||
|
if (StringUtils.endsWith(sqlVariableDetails.getId(), START_END_SEPARATOR)) {
|
||||||
|
return simpleDateFormat.format(new Date(Long.parseLong((String) sqlVariableDetails.getValue().get(1))));
|
||||||
|
} else {
|
||||||
|
return simpleDateFormat.format(new Date(Long.parseLong((String) sqlVariableDetails.getValue().get(0))));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (StringUtils.endsWith(sqlVariableDetails.getId(), START_END_SEPARATOR)) {
|
||||||
|
return sqlVariableDetails.getValue().get(1);
|
||||||
|
} else {
|
||||||
|
return sqlVariableDetails.getValue().get(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return (String) sqlVariableDetails.getValue().get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private String handleSubstitutedSql(String sql) {
|
||||||
|
if (sql.contains(SysParamsSubstitutedParams) && userEntity != null) {
|
||||||
|
sql = sql.replace(SysParamsSubstitutedParams + "sysParams.userId", userEntity.getAccount());
|
||||||
|
sql = sql.replace(SysParamsSubstitutedParams + "sysParams.userEmail", userEntity.getEmail());
|
||||||
|
sql = sql.replace(SysParamsSubstitutedParams + "sysParams.userName", userEntity.getName());
|
||||||
|
for (SysVariableValueItem variable : userEntity.getVariables()) {
|
||||||
|
String value = null;
|
||||||
|
if (!variable.isValid()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (variable.getSysVariableDto().getType().equalsIgnoreCase("text")) {
|
||||||
|
for (SysVariableValueDto sysVariableValueDto : variable.getValueList()) {
|
||||||
|
if (variable.getVariableValueIds().contains(sysVariableValueDto.getId().toString())) {
|
||||||
|
value = sysVariableValueDto.getValue();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
value = variable.getVariableValue();
|
||||||
|
}
|
||||||
|
if (StringUtils.isNotEmpty(value)) {
|
||||||
|
sql = sql.replace(SysParamsSubstitutedParams + variable.getVariableId(), value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sql;
|
||||||
|
} else {
|
||||||
|
return SubstitutedSql;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private String handleSubstitutedSqlForIn(String sql) {
|
||||||
|
if (sql.contains(SysParamsSubstitutedParams) && userEntity != null) {
|
||||||
|
for (SysVariableValueItem variable : userEntity.getVariables()) {
|
||||||
|
List<String> values = new ArrayList<>();
|
||||||
|
if (!variable.isValid()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (variable.getSysVariableDto().getType().equalsIgnoreCase("text")) {
|
||||||
|
|
||||||
|
for (SysVariableValueDto sysVariableValueDto : variable.getValueList()) {
|
||||||
|
if (variable.getVariableValueIds().contains(sysVariableValueDto.getId().toString())) {
|
||||||
|
values.add(sysVariableValueDto.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (CollectionUtils.isNotEmpty(values)) {
|
||||||
|
sql = sql.replace(SysParamsSubstitutedParams + variable.getVariableId(), "'" + String.join("','", values) + "'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sql;
|
||||||
|
} else {
|
||||||
|
return SubstitutedSql;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,34 @@
|
|||||||
|
package io.dataease.commons.utils;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLConnection;
|
||||||
|
|
||||||
|
public class UrlTestUtils {
|
||||||
|
|
||||||
|
public static boolean testUrlWithTimeOut(String urlString, int timeOutMillSeconds) {
|
||||||
|
try {
|
||||||
|
URL url = new URL(urlString);
|
||||||
|
URLConnection co = url.openConnection();
|
||||||
|
co.setConnectTimeout(timeOutMillSeconds);
|
||||||
|
co.connect();
|
||||||
|
return true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isURLAvailable(String urlString) {
|
||||||
|
try {
|
||||||
|
URL url = new URL(urlString);
|
||||||
|
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||||
|
connection.setRequestMethod("HEAD");
|
||||||
|
int responseCode = connection.getResponseCode();
|
||||||
|
return responseCode == HttpURLConnection.HTTP_OK;
|
||||||
|
} catch (IOException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
package io.dataease.config;
|
||||||
|
|
||||||
|
import com.fit2cloud.autoconfigure.QuartzAutoConfiguration;
|
||||||
|
import io.dataease.utils.CommonThreadPool;
|
||||||
|
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@AutoConfigureBefore(QuartzAutoConfiguration.class)
|
||||||
|
public class CommonConfig {
|
||||||
|
|
||||||
|
@Bean(destroyMethod = "shutdown")
|
||||||
|
public CommonThreadPool resourcePoolThreadPool() {
|
||||||
|
CommonThreadPool commonThreadPool = new CommonThreadPool();
|
||||||
|
commonThreadPool.setCorePoolSize(50);
|
||||||
|
commonThreadPool.setMaxQueueSize(100);
|
||||||
|
commonThreadPool.setKeepAliveSeconds(3600);
|
||||||
|
return commonThreadPool;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
package io.dataease.config;
|
||||||
|
|
||||||
|
import io.dataease.constant.AuthConstant;
|
||||||
|
import io.dataease.share.interceptor.LinkInterceptor;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||||
|
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||||
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||||
|
|
||||||
|
import static io.dataease.constant.StaticResourceConstants.*;
|
||||||
|
import static io.dataease.utils.StaticResourceUtils.ensureBoth;
|
||||||
|
import static io.dataease.utils.StaticResourceUtils.ensureSuffix;
|
||||||
|
@Configuration
|
||||||
|
public class DeMvcConfig implements WebMvcConfigurer {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private LinkInterceptor linkInterceptor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuring static resource path
|
||||||
|
*
|
||||||
|
* @param registry registry
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
||||||
|
String workDir = FILE_PROTOCOL + ensureSuffix(WORK_DIR, FILE_SEPARATOR);
|
||||||
|
String uploadUrlPattern = ensureBoth(URL_SEPARATOR + UPLOAD_URL_PREFIX, AuthConstant.DE_API_PREFIX, URL_SEPARATOR) + "**";
|
||||||
|
registry.addResourceHandler(uploadUrlPattern).addResourceLocations(workDir);
|
||||||
|
|
||||||
|
// map
|
||||||
|
String mapDir = FILE_PROTOCOL + ensureSuffix(MAP_DIR, FILE_SEPARATOR);
|
||||||
|
String mapUrlPattern = ensureBoth(MAP_URL, AuthConstant.DE_API_PREFIX, URL_SEPARATOR) + "**";
|
||||||
|
registry.addResourceHandler(mapUrlPattern).addResourceLocations(mapDir);
|
||||||
|
|
||||||
|
String geoDir = FILE_PROTOCOL + ensureSuffix(CUSTOM_MAP_DIR, FILE_SEPARATOR);
|
||||||
|
String geoUrlPattern = ensureBoth(GEO_URL, AuthConstant.DE_API_PREFIX, URL_SEPARATOR) + "**";
|
||||||
|
registry.addResourceHandler(geoUrlPattern).addResourceLocations(geoDir);
|
||||||
|
|
||||||
|
String i18nDir = FILE_PROTOCOL + ensureSuffix(I18N_DIR, FILE_SEPARATOR);
|
||||||
|
String i18nUrlPattern = ensureBoth(I18N_URL, AuthConstant.DE_API_PREFIX, URL_SEPARATOR) + "**";
|
||||||
|
registry.addResourceHandler(i18nUrlPattern).addResourceLocations(i18nDir);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addInterceptors(InterceptorRegistry registry) {
|
||||||
|
registry.addInterceptor(linkInterceptor).addPathPatterns("/**");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
package io.dataease.config;
|
||||||
|
|
||||||
|
|
||||||
|
import io.dataease.commons.utils.MybatisInterceptorConfig;
|
||||||
|
import io.dataease.datasource.dao.auto.entity.CoreDatasource;
|
||||||
|
import io.dataease.datasource.dao.auto.entity.CoreDeEngine;
|
||||||
|
import io.dataease.interceptor.MybatisInterceptor;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableTransactionManagement
|
||||||
|
public class MybatisConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean
|
||||||
|
public MybatisInterceptor dbInterceptor() {
|
||||||
|
MybatisInterceptor interceptor = new MybatisInterceptor();
|
||||||
|
List<MybatisInterceptorConfig> configList = new ArrayList<>();
|
||||||
|
configList.add(new MybatisInterceptorConfig(CoreDeEngine.class, "configuration"));
|
||||||
|
configList.add(new MybatisInterceptorConfig(CoreDatasource.class, "configuration"));
|
||||||
|
interceptor.setInterceptorConfigList(configList);
|
||||||
|
return interceptor;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,102 @@
|
|||||||
|
package io.dataease.copilot.api;
|
||||||
|
|
||||||
|
import io.dataease.api.copilot.dto.ReceiveDTO;
|
||||||
|
import io.dataease.api.copilot.dto.SendDTO;
|
||||||
|
import io.dataease.copilot.dao.auto.entity.CoreCopilotConfig;
|
||||||
|
import io.dataease.copilot.dao.auto.mapper.CoreCopilotConfigMapper;
|
||||||
|
import io.dataease.exception.DEException;
|
||||||
|
import io.dataease.utils.HttpClientConfig;
|
||||||
|
import io.dataease.utils.HttpClientUtil;
|
||||||
|
import io.dataease.utils.JsonUtil;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.http.Header;
|
||||||
|
import org.apache.http.HttpResponse;
|
||||||
|
import org.json.simple.JSONObject;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Base64;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author Junjun
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class CopilotAPI {
|
||||||
|
|
||||||
|
public static final String TOKEN = "/auth/token/license";
|
||||||
|
|
||||||
|
public static final String FREE_TOKEN = "/auth/token/free";
|
||||||
|
|
||||||
|
public static final String API = "/copilot/v1";
|
||||||
|
|
||||||
|
public static final String CHART = "/generate-chart";
|
||||||
|
|
||||||
|
public static final String RATE_LIMIT = "/rate-limit";
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private CoreCopilotConfigMapper coreCopilotConfigMapper;
|
||||||
|
|
||||||
|
public String basicAuth(String userName, String password) {
|
||||||
|
String auth = userName + ":" + password;
|
||||||
|
String encodedAuth = Base64.getEncoder().encodeToString(auth.getBytes());
|
||||||
|
return "Basic " + encodedAuth;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String bearerAuth(String token) {
|
||||||
|
return "Bearer " + token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CoreCopilotConfig getConfig() {
|
||||||
|
CoreCopilotConfig coreCopilotConfig = coreCopilotConfigMapper.selectById(1);
|
||||||
|
coreCopilotConfig.setPwd(new String(Base64.getDecoder().decode(coreCopilotConfig.getPwd())));
|
||||||
|
return coreCopilotConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getToken(String license) throws Exception {
|
||||||
|
String url = getConfig().getCopilotUrl() + TOKEN;
|
||||||
|
JSONObject json = new JSONObject();
|
||||||
|
json.put("licenseText", license);
|
||||||
|
HttpClientConfig httpClientConfig = new HttpClientConfig();
|
||||||
|
String tokenJson = HttpClientUtil.post(url, json.toString(), httpClientConfig);
|
||||||
|
return (String) JsonUtil.parse(tokenJson, Map.class).get("accessToken");
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFreeToken() throws Exception {
|
||||||
|
String url = getConfig().getCopilotUrl() + FREE_TOKEN;
|
||||||
|
HttpClientConfig httpClientConfig = new HttpClientConfig();
|
||||||
|
String tokenJson = HttpClientUtil.post(url, "", httpClientConfig);
|
||||||
|
return (String) JsonUtil.parse(tokenJson, Map.class).get("accessToken");
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReceiveDTO generateChart(String token, SendDTO sendDTO) {
|
||||||
|
String url = getConfig().getCopilotUrl() + API + CHART;
|
||||||
|
String request = (String) JsonUtil.toJSONString(sendDTO);
|
||||||
|
HttpClientConfig httpClientConfig = new HttpClientConfig();
|
||||||
|
httpClientConfig.addHeader("Authorization", bearerAuth(token));
|
||||||
|
String result = HttpClientUtil.post(url, request, httpClientConfig);
|
||||||
|
return JsonUtil.parseObject(result, ReceiveDTO.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkRateLimit(String token) {
|
||||||
|
String url = getConfig().getCopilotUrl() + API + RATE_LIMIT;
|
||||||
|
HttpClientConfig httpClientConfig = new HttpClientConfig();
|
||||||
|
httpClientConfig.addHeader("Authorization", bearerAuth(token));
|
||||||
|
HttpResponse httpResponse = HttpClientUtil.postWithHeaders(url, null, httpClientConfig);
|
||||||
|
Header[] allHeaders = httpResponse.getAllHeaders();
|
||||||
|
|
||||||
|
String limit = "";
|
||||||
|
String seconds = "";
|
||||||
|
for (Header header : allHeaders) {
|
||||||
|
if (StringUtils.equalsIgnoreCase(header.getName(), "x-rate-limit-remaining")) {
|
||||||
|
limit = header.getValue();
|
||||||
|
}
|
||||||
|
if (StringUtils.equalsIgnoreCase(header.getName(), "x-rate-limit-retry-after-seconds")) {
|
||||||
|
seconds = header.getValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Long.parseLong(limit) <= 0) {
|
||||||
|
DEException.throwException(String.format("当前请求频率已达上限,请在%s秒后重试", seconds));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,71 @@
|
|||||||
|
package io.dataease.copilot.dao.auto.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
*
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author fit2cloud
|
||||||
|
* @since 2024-07-08
|
||||||
|
*/
|
||||||
|
@TableName("core_copilot_config")
|
||||||
|
public class CoreCopilotConfig implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ID
|
||||||
|
*/
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private String copilotUrl;
|
||||||
|
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
private String pwd;
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCopilotUrl() {
|
||||||
|
return copilotUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCopilotUrl(String copilotUrl) {
|
||||||
|
this.copilotUrl = copilotUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsername(String username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPwd() {
|
||||||
|
return pwd;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPwd(String pwd) {
|
||||||
|
this.pwd = pwd;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "CoreCopilotConfig{" +
|
||||||
|
"id = " + id +
|
||||||
|
", copilotUrl = " + copilotUrl +
|
||||||
|
", username = " + username +
|
||||||
|
", pwd = " + pwd +
|
||||||
|
"}";
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,276 @@
|
|||||||
|
package io.dataease.copilot.dao.auto.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
*
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author fit2cloud
|
||||||
|
* @since 2024-07-04
|
||||||
|
*/
|
||||||
|
@TableName("core_copilot_msg")
|
||||||
|
public class CoreCopilotMsg implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ID
|
||||||
|
*/
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户ID
|
||||||
|
*/
|
||||||
|
private Long userId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数据集ID
|
||||||
|
*/
|
||||||
|
private Long datasetGroupId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* user or api
|
||||||
|
*/
|
||||||
|
private String msgType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mysql oracle ...
|
||||||
|
*/
|
||||||
|
private String engineType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* create sql
|
||||||
|
*/
|
||||||
|
private String schemaSql;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户提问
|
||||||
|
*/
|
||||||
|
private String question;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 历史信息
|
||||||
|
*/
|
||||||
|
private String history;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* copilot 返回 sql
|
||||||
|
*/
|
||||||
|
private String copilotSql;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* copilot 返回信息
|
||||||
|
*/
|
||||||
|
private String apiMsg;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sql 状态
|
||||||
|
*/
|
||||||
|
private Integer sqlOk;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* chart 状态
|
||||||
|
*/
|
||||||
|
private Integer chartOk;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* chart 内容
|
||||||
|
*/
|
||||||
|
private String chart;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 视图数据
|
||||||
|
*/
|
||||||
|
private String chartData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行请求的SQL
|
||||||
|
*/
|
||||||
|
private String execSql;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* msg状态,0失败 1成功
|
||||||
|
*/
|
||||||
|
private Integer msgStatus;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* de错误信息
|
||||||
|
*/
|
||||||
|
private String errMsg;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建时间
|
||||||
|
*/
|
||||||
|
private Long createTime;
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getUserId() {
|
||||||
|
return userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUserId(Long userId) {
|
||||||
|
this.userId = userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getDatasetGroupId() {
|
||||||
|
return datasetGroupId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDatasetGroupId(Long datasetGroupId) {
|
||||||
|
this.datasetGroupId = datasetGroupId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMsgType() {
|
||||||
|
return msgType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMsgType(String msgType) {
|
||||||
|
this.msgType = msgType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEngineType() {
|
||||||
|
return engineType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEngineType(String engineType) {
|
||||||
|
this.engineType = engineType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSchemaSql() {
|
||||||
|
return schemaSql;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSchemaSql(String schemaSql) {
|
||||||
|
this.schemaSql = schemaSql;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getQuestion() {
|
||||||
|
return question;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setQuestion(String question) {
|
||||||
|
this.question = question;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getHistory() {
|
||||||
|
return history;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHistory(String history) {
|
||||||
|
this.history = history;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCopilotSql() {
|
||||||
|
return copilotSql;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCopilotSql(String copilotSql) {
|
||||||
|
this.copilotSql = copilotSql;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getApiMsg() {
|
||||||
|
return apiMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setApiMsg(String apiMsg) {
|
||||||
|
this.apiMsg = apiMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getSqlOk() {
|
||||||
|
return sqlOk;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSqlOk(Integer sqlOk) {
|
||||||
|
this.sqlOk = sqlOk;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getChartOk() {
|
||||||
|
return chartOk;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setChartOk(Integer chartOk) {
|
||||||
|
this.chartOk = chartOk;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getChart() {
|
||||||
|
return chart;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setChart(String chart) {
|
||||||
|
this.chart = chart;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getChartData() {
|
||||||
|
return chartData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setChartData(String chartData) {
|
||||||
|
this.chartData = chartData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getExecSql() {
|
||||||
|
return execSql;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExecSql(String execSql) {
|
||||||
|
this.execSql = execSql;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getMsgStatus() {
|
||||||
|
return msgStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMsgStatus(Integer msgStatus) {
|
||||||
|
this.msgStatus = msgStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getErrMsg() {
|
||||||
|
return errMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setErrMsg(String errMsg) {
|
||||||
|
this.errMsg = errMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getCreateTime() {
|
||||||
|
return createTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreateTime(Long createTime) {
|
||||||
|
this.createTime = createTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "CoreCopilotMsg{" +
|
||||||
|
"id = " + id +
|
||||||
|
", userId = " + userId +
|
||||||
|
", datasetGroupId = " + datasetGroupId +
|
||||||
|
", msgType = " + msgType +
|
||||||
|
", engineType = " + engineType +
|
||||||
|
", schemaSql = " + schemaSql +
|
||||||
|
", question = " + question +
|
||||||
|
", history = " + history +
|
||||||
|
", copilotSql = " + copilotSql +
|
||||||
|
", apiMsg = " + apiMsg +
|
||||||
|
", sqlOk = " + sqlOk +
|
||||||
|
", chartOk = " + chartOk +
|
||||||
|
", chart = " + chart +
|
||||||
|
", chartData = " + chartData +
|
||||||
|
", execSql = " + execSql +
|
||||||
|
", msgStatus = " + msgStatus +
|
||||||
|
", errMsg = " + errMsg +
|
||||||
|
", createTime = " + createTime +
|
||||||
|
"}";
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,74 @@
|
|||||||
|
package io.dataease.copilot.dao.auto.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
*
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author fit2cloud
|
||||||
|
* @since 2024-07-08
|
||||||
|
*/
|
||||||
|
@TableName("core_copilot_token")
|
||||||
|
public class CoreCopilotToken implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ID
|
||||||
|
*/
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* free or license
|
||||||
|
*/
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
private String token;
|
||||||
|
|
||||||
|
private Long updateTime;
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(String type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getToken() {
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setToken(String token) {
|
||||||
|
this.token = token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getUpdateTime() {
|
||||||
|
return updateTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUpdateTime(Long updateTime) {
|
||||||
|
this.updateTime = updateTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "CoreCopilotToken{" +
|
||||||
|
"id = " + id +
|
||||||
|
", type = " + type +
|
||||||
|
", token = " + token +
|
||||||
|
", updateTime = " + updateTime +
|
||||||
|
"}";
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package io.dataease.copilot.dao.auto.mapper;
|
||||||
|
|
||||||
|
import io.dataease.copilot.dao.auto.entity.CoreCopilotConfig;
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Mapper 接口
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author fit2cloud
|
||||||
|
* @since 2024-07-08
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface CoreCopilotConfigMapper extends BaseMapper<CoreCopilotConfig> {
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package io.dataease.copilot.dao.auto.mapper;
|
||||||
|
|
||||||
|
import io.dataease.copilot.dao.auto.entity.CoreCopilotMsg;
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Mapper 接口
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author fit2cloud
|
||||||
|
* @since 2024-07-04
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface CoreCopilotMsgMapper extends BaseMapper<CoreCopilotMsg> {
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package io.dataease.copilot.dao.auto.mapper;
|
||||||
|
|
||||||
|
import io.dataease.copilot.dao.auto.entity.CoreCopilotToken;
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Mapper 接口
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author fit2cloud
|
||||||
|
* @since 2024-07-08
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface CoreCopilotTokenMapper extends BaseMapper<CoreCopilotToken> {
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,487 @@
|
|||||||
|
package io.dataease.copilot.manage;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
|
import io.dataease.api.copilot.dto.*;
|
||||||
|
import io.dataease.api.dataset.union.DatasetGroupInfoDTO;
|
||||||
|
import io.dataease.api.dataset.union.UnionDTO;
|
||||||
|
import io.dataease.chart.utils.ChartDataBuild;
|
||||||
|
import io.dataease.copilot.api.CopilotAPI;
|
||||||
|
import io.dataease.dataset.dao.auto.entity.CoreDatasetGroup;
|
||||||
|
import io.dataease.dataset.dao.auto.mapper.CoreDatasetGroupMapper;
|
||||||
|
import io.dataease.dataset.manage.DatasetDataManage;
|
||||||
|
import io.dataease.dataset.manage.DatasetSQLManage;
|
||||||
|
import io.dataease.dataset.manage.DatasetTableFieldManage;
|
||||||
|
import io.dataease.dataset.manage.PermissionManage;
|
||||||
|
import io.dataease.dataset.utils.FieldUtils;
|
||||||
|
import io.dataease.constant.DeTypeConstants;
|
||||||
|
import io.dataease.engine.utils.Utils;
|
||||||
|
import io.dataease.exception.DEException;
|
||||||
|
import io.dataease.extensions.datasource.constant.SqlPlaceholderConstants;
|
||||||
|
import io.dataease.extensions.datasource.dto.DatasetTableFieldDTO;
|
||||||
|
import io.dataease.extensions.datasource.dto.DatasourceRequest;
|
||||||
|
import io.dataease.extensions.datasource.dto.DatasourceSchemaDTO;
|
||||||
|
import io.dataease.extensions.datasource.dto.TableField;
|
||||||
|
import io.dataease.extensions.datasource.factory.ProviderFactory;
|
||||||
|
import io.dataease.extensions.datasource.provider.Provider;
|
||||||
|
import io.dataease.extensions.view.dto.ColumnPermissionItem;
|
||||||
|
import io.dataease.i18n.Translator;
|
||||||
|
import io.dataease.license.dao.po.LicensePO;
|
||||||
|
import io.dataease.license.manage.F2CLicManage;
|
||||||
|
import io.dataease.license.utils.LicenseUtil;
|
||||||
|
import io.dataease.utils.AuthUtils;
|
||||||
|
import io.dataease.utils.BeanUtils;
|
||||||
|
import io.dataease.utils.JsonUtil;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.apache.calcite.config.Lex;
|
||||||
|
import org.apache.calcite.sql.SqlDialect;
|
||||||
|
import org.apache.calcite.sql.SqlNode;
|
||||||
|
import org.apache.calcite.sql.parser.SqlParser;
|
||||||
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author Junjun
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class CopilotManage {
|
||||||
|
@Resource
|
||||||
|
private DatasetSQLManage datasetSQLManage;
|
||||||
|
@Resource
|
||||||
|
private CoreDatasetGroupMapper coreDatasetGroupMapper;
|
||||||
|
@Resource
|
||||||
|
private DatasetTableFieldManage datasetTableFieldManage;
|
||||||
|
@Resource
|
||||||
|
private DatasetDataManage datasetDataManage;
|
||||||
|
@Resource
|
||||||
|
private PermissionManage permissionManage;
|
||||||
|
@Resource
|
||||||
|
private MsgManage msgManage;
|
||||||
|
|
||||||
|
private static Logger logger = LoggerFactory.getLogger(CopilotManage.class);
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private TokenManage tokenManage;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private CopilotAPI copilotAPI;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private F2CLicManage f2CLicManage;
|
||||||
|
|
||||||
|
private String[] chartType = {"bar", "line", "pie"};
|
||||||
|
|
||||||
|
public MsgDTO chat(MsgDTO msgDTO) throws Exception {
|
||||||
|
CoreDatasetGroup coreDatasetGroup = coreDatasetGroupMapper.selectById(msgDTO.getDatasetGroupId());
|
||||||
|
if (coreDatasetGroup == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
DatasetGroupInfoDTO dto = new DatasetGroupInfoDTO();
|
||||||
|
BeanUtils.copyBean(dto, coreDatasetGroup);
|
||||||
|
dto.setUnionSql(null);
|
||||||
|
List<UnionDTO> unionDTOList = JsonUtil.parseList(coreDatasetGroup.getInfo(), new TypeReference<>() {
|
||||||
|
});
|
||||||
|
dto.setUnion(unionDTOList);
|
||||||
|
|
||||||
|
// 获取field
|
||||||
|
List<DatasetTableFieldDTO> dsFields = datasetTableFieldManage.selectByDatasetGroupId(msgDTO.getDatasetGroupId());
|
||||||
|
List<DatasetTableFieldDTO> allFields = dsFields.stream().filter(ele -> ele.getExtField() == 0)
|
||||||
|
.map(ele -> {
|
||||||
|
DatasetTableFieldDTO datasetTableFieldDTO = new DatasetTableFieldDTO();
|
||||||
|
BeanUtils.copyBean(datasetTableFieldDTO, ele);
|
||||||
|
datasetTableFieldDTO.setFieldShortName(ele.getDataeaseName());
|
||||||
|
return datasetTableFieldDTO;
|
||||||
|
}).collect(Collectors.toList());
|
||||||
|
|
||||||
|
Map<String, Object> sqlMap = datasetSQLManage.getUnionSQLForEdit(dto, null);
|
||||||
|
String sql = (String) sqlMap.get("sql");// 数据集原始SQL
|
||||||
|
Map<Long, DatasourceSchemaDTO> dsMap = (Map<Long, DatasourceSchemaDTO>) sqlMap.get("dsMap");
|
||||||
|
boolean crossDs = Utils.isCrossDs(dsMap);
|
||||||
|
if (crossDs) {
|
||||||
|
DEException.throwException(Translator.get("i18n_copilot_cross_ds_error"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调用copilot service 获取SQL和chart struct,将返回SQL中表名替换成数据集SQL
|
||||||
|
// deSendDTO 构建schema和engine
|
||||||
|
if (ObjectUtils.isEmpty(dsMap)) {
|
||||||
|
DEException.throwException("No datasource");
|
||||||
|
}
|
||||||
|
|
||||||
|
DatasourceSchemaDTO ds = dsMap.entrySet().iterator().next().getValue();
|
||||||
|
String type = engine(ds.getType());// 数据库类型,如mysql,oracle等,可能需要映射成copilot需要的类型
|
||||||
|
|
||||||
|
datasetDataManage.buildFieldName(sqlMap, allFields);
|
||||||
|
List<String> strings = transCreateTableFields(allFields);
|
||||||
|
String createSql = "CREATE TABLE de_tmp_table (" + StringUtils.join(strings, ",") + ")";
|
||||||
|
logger.debug("Copilot Schema SQL: " + createSql);
|
||||||
|
|
||||||
|
// PerMsgDTO perMsgDTO = new PerMsgDTO();
|
||||||
|
msgDTO.setDatasetGroupId(dto.getId());
|
||||||
|
msgDTO.setMsgType("user");
|
||||||
|
msgDTO.setEngineType(type);
|
||||||
|
msgDTO.setSchemaSql(createSql);
|
||||||
|
msgDTO.setHistory(msgDTO.getHistory());
|
||||||
|
msgDTO.setMsgStatus(1);
|
||||||
|
msgManage.save(msgDTO);// 到这里为止,提问所需参数构建完毕,往数据库插入一条提问记录
|
||||||
|
|
||||||
|
DESendDTO deSendDTO = new DESendDTO();
|
||||||
|
deSendDTO.setDatasetGroupId(dto.getId());
|
||||||
|
deSendDTO.setQuestion(msgDTO.getQuestion());
|
||||||
|
deSendDTO.setHistory(msgDTO.getHistory());
|
||||||
|
deSendDTO.setEngine(type);
|
||||||
|
deSendDTO.setSchema(createSql);
|
||||||
|
|
||||||
|
// do copilot chat
|
||||||
|
ReceiveDTO receiveDTO = copilotChat(deSendDTO);
|
||||||
|
|
||||||
|
// copilot 请求结束,继续de获取数据
|
||||||
|
// 获取数据集相关行列权限、最终再套一层SQL
|
||||||
|
Map<String, ColumnPermissionItem> desensitizationList = new HashMap<>();
|
||||||
|
allFields = permissionManage.filterColumnPermissions(allFields, desensitizationList, dto.getId(), null);
|
||||||
|
if (ObjectUtils.isEmpty(allFields)) {
|
||||||
|
DEException.throwException(Translator.get("i18n_no_column_permission"));
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> dsList = new ArrayList<>();
|
||||||
|
for (Map.Entry<Long, DatasourceSchemaDTO> next : dsMap.entrySet()) {
|
||||||
|
dsList.add(next.getValue().getType());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!crossDs) {
|
||||||
|
sql = Utils.replaceSchemaAlias(sql, dsMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
Provider provider;
|
||||||
|
if (crossDs) {
|
||||||
|
provider = ProviderFactory.getDefaultProvider();
|
||||||
|
} else {
|
||||||
|
provider = ProviderFactory.getProvider(dsList.getFirst());
|
||||||
|
}
|
||||||
|
|
||||||
|
// List<DataSetRowPermissionsTreeDTO> rowPermissionsTree = new ArrayList<>();
|
||||||
|
// TokenUserBO user = AuthUtils.getUser();
|
||||||
|
// if (user != null) {
|
||||||
|
// rowPermissionsTree = permissionManage.getRowPermissionsTree(dto.getId(), user.getUserId());
|
||||||
|
// }
|
||||||
|
|
||||||
|
// build query sql
|
||||||
|
// SQLMeta sqlMeta = new SQLMeta();
|
||||||
|
// Table2SQLObj.table2sqlobj(sqlMeta, null, "(" + sql + ")", crossDs);
|
||||||
|
// Field2SQLObj.field2sqlObj(sqlMeta, allFields, allFields, crossDs, dsMap);
|
||||||
|
// WhereTree2Str.transFilterTrees(sqlMeta, rowPermissionsTree, allFields, crossDs, dsMap);
|
||||||
|
// Order2SQLObj.getOrders(sqlMeta, dto.getSortFields(), allFields, crossDs, dsMap);
|
||||||
|
// String querySQL = SQLProvider.createQuerySQL(sqlMeta, false, false, needOrder);
|
||||||
|
// querySQL = provider.rebuildSQL(querySQL, sqlMeta, crossDs, dsMap);
|
||||||
|
// logger.debug("preview sql: " + querySQL);
|
||||||
|
|
||||||
|
// 无法加行权限的情况下,直接用sql
|
||||||
|
String querySQL = sql;
|
||||||
|
|
||||||
|
String copilotSQL = receiveDTO.getSql();
|
||||||
|
// 用calcite尝试将SQL转方言,如果失败了,就按照原SQL执行
|
||||||
|
// copilotSQL = transSql(type, copilotSQL, provider, receiveDTO);
|
||||||
|
|
||||||
|
// 通过数据源请求数据
|
||||||
|
// 调用数据源的calcite获得data
|
||||||
|
DatasourceRequest datasourceRequest = new DatasourceRequest();
|
||||||
|
datasourceRequest.setDsList(dsMap);
|
||||||
|
String s = "";
|
||||||
|
Map<String, Object> data;
|
||||||
|
try {
|
||||||
|
s = copilotSQL
|
||||||
|
.replaceAll(SqlPlaceholderConstants.KEYWORD_PREFIX_REGEX + "de_tmp_table" + SqlPlaceholderConstants.KEYWORD_SUFFIX_REGEX, "(" + querySQL + ")")
|
||||||
|
.replaceAll(SqlPlaceholderConstants.KEYWORD_PREFIX_REGEX + "DE_TMP_TABLE" + SqlPlaceholderConstants.KEYWORD_SUFFIX_REGEX, "(" + querySQL + ")");
|
||||||
|
logger.debug("copilot sql: " + s);
|
||||||
|
datasourceRequest.setQuery(s);
|
||||||
|
data = provider.fetchResultField(datasourceRequest);
|
||||||
|
} catch (Exception e) {
|
||||||
|
try {
|
||||||
|
s = copilotSQL
|
||||||
|
.replaceAll(SqlPlaceholderConstants.KEYWORD_PREFIX_REGEX + "de_tmp_table" + SqlPlaceholderConstants.KEYWORD_SUFFIX_REGEX, "(" + querySQL + ") tmp")
|
||||||
|
.replaceAll(SqlPlaceholderConstants.KEYWORD_PREFIX_REGEX + "DE_TMP_TABLE" + SqlPlaceholderConstants.KEYWORD_SUFFIX_REGEX, "(" + querySQL + ") tmp");
|
||||||
|
logger.debug("copilot sql: " + s);
|
||||||
|
datasourceRequest.setQuery(s);
|
||||||
|
data = provider.fetchResultField(datasourceRequest);
|
||||||
|
} catch (Exception e1) {
|
||||||
|
// 如果异常,则获取最后一条成功的history
|
||||||
|
MsgDTO lastSuccessMsg = msgManage.getLastSuccessMsg(AuthUtils.getUser().getUserId(), dto.getId());
|
||||||
|
// 请求数据出错,记录错误信息和copilot返回的信息
|
||||||
|
MsgDTO result = new MsgDTO();
|
||||||
|
result.setDatasetGroupId(dto.getId());
|
||||||
|
result.setMsgType("api");
|
||||||
|
result.setHistory(lastSuccessMsg == null ? new ArrayList<>() : lastSuccessMsg.getHistory());
|
||||||
|
result.setCopilotSql(receiveDTO.getSql());
|
||||||
|
result.setApiMsg(receiveDTO.getApiMessage());
|
||||||
|
result.setSqlOk(receiveDTO.getSqlOk() ? 1 : 0);
|
||||||
|
result.setChartOk(receiveDTO.getChartOk() ? 1 : 0);
|
||||||
|
result.setChart(receiveDTO.getChart());
|
||||||
|
result.setExecSql(s);
|
||||||
|
result.setMsgStatus(0);
|
||||||
|
result.setErrMsg(e1.getMessage());
|
||||||
|
msgManage.save(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<TableField> fields = (List<TableField>) data.get("fields");
|
||||||
|
fields = transField(fields);
|
||||||
|
Map<String, Object> map = new LinkedHashMap<>();
|
||||||
|
// 重新构造data
|
||||||
|
Map<String, Object> previewData = buildPreviewData(data, fields, desensitizationList);
|
||||||
|
|
||||||
|
map.put("data", previewData);
|
||||||
|
map.put("sql", Base64.getEncoder().encodeToString(s.getBytes()));
|
||||||
|
|
||||||
|
// 重构chart结构,补全缺失字段
|
||||||
|
rebuildChart(receiveDTO, fields);
|
||||||
|
|
||||||
|
MsgDTO result = new MsgDTO();
|
||||||
|
result.setDatasetGroupId(dto.getId());
|
||||||
|
result.setMsgType("api");
|
||||||
|
result.setHistory(receiveDTO.getHistory());
|
||||||
|
result.setCopilotSql(receiveDTO.getSql());
|
||||||
|
result.setApiMsg(receiveDTO.getApiMessage());
|
||||||
|
result.setSqlOk(receiveDTO.getSqlOk() ? 1 : 0);
|
||||||
|
result.setChartOk(receiveDTO.getChartOk() ? 1 : 0);
|
||||||
|
result.setChart(receiveDTO.getChart());
|
||||||
|
result.setChartData(map);
|
||||||
|
result.setExecSql(s);
|
||||||
|
result.setMsgStatus(1);
|
||||||
|
msgManage.save(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReceiveDTO copilotChat(DESendDTO deSendDTO) throws Exception {
|
||||||
|
boolean valid = LicenseUtil.licenseValid();
|
||||||
|
// call copilot service
|
||||||
|
TokenDTO tokenDTO = tokenManage.getToken(valid);
|
||||||
|
ReceiveDTO receiveDTO;
|
||||||
|
if (StringUtils.isEmpty(tokenDTO.getToken())) {
|
||||||
|
// get token
|
||||||
|
String token;
|
||||||
|
if (valid) {
|
||||||
|
LicensePO read = f2CLicManage.read();
|
||||||
|
token = copilotAPI.getToken(read.getLicense());
|
||||||
|
} else {
|
||||||
|
token = copilotAPI.getFreeToken();
|
||||||
|
}
|
||||||
|
tokenManage.updateToken(token, valid);
|
||||||
|
receiveDTO = copilotAPI.generateChart(token, deSendDTO);
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
receiveDTO = copilotAPI.generateChart(tokenDTO.getToken(), deSendDTO);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// error, get token again
|
||||||
|
String token;
|
||||||
|
if (valid) {
|
||||||
|
LicensePO read = f2CLicManage.read();
|
||||||
|
token = copilotAPI.getToken(read.getLicense());
|
||||||
|
} else {
|
||||||
|
token = copilotAPI.getFreeToken();
|
||||||
|
}
|
||||||
|
tokenManage.updateToken(token, valid);
|
||||||
|
throw new Exception(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!receiveDTO.getSqlOk() || !receiveDTO.getChartOk()) {
|
||||||
|
DEException.throwException((String) JsonUtil.toJSONString(receiveDTO));
|
||||||
|
}
|
||||||
|
logger.debug("Copilot Service SQL: " + receiveDTO.getSql());
|
||||||
|
logger.debug("Copilot Service Chart: " + JsonUtil.toJSONString(receiveDTO.getChart()));
|
||||||
|
return receiveDTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void rebuildChart(ReceiveDTO receiveDTO, List<TableField> fields) {
|
||||||
|
if (StringUtils.equalsIgnoreCase(receiveDTO.getChart().getType(), "pie")) {
|
||||||
|
AxisFieldDTO column = receiveDTO.getChart().getColumn();
|
||||||
|
if (fields.size() != 2 || column == null) {
|
||||||
|
DEException.throwException("build pie error: " + JsonUtil.toJSONString(receiveDTO));
|
||||||
|
}
|
||||||
|
AxisDTO axisDTO = new AxisDTO();
|
||||||
|
AxisFieldDTO x = new AxisFieldDTO();
|
||||||
|
AxisFieldDTO y = new AxisFieldDTO();
|
||||||
|
if (StringUtils.equals(fields.get(0).getOriginName(), column.getValue())) {
|
||||||
|
x.setName(column.getName());
|
||||||
|
x.setValue(column.getValue());
|
||||||
|
y.setName(fields.get(1).getOriginName());
|
||||||
|
y.setValue(fields.get(1).getOriginName());
|
||||||
|
} else if (StringUtils.equals(fields.get(1).getOriginName(), column.getValue())) {
|
||||||
|
x.setName(fields.get(0).getOriginName());
|
||||||
|
x.setValue(fields.get(0).getOriginName());
|
||||||
|
y.setName(column.getName());
|
||||||
|
y.setValue(column.getValue());
|
||||||
|
} else {
|
||||||
|
DEException.throwException("build pie error: " + JsonUtil.toJSONString(receiveDTO));
|
||||||
|
}
|
||||||
|
axisDTO.setX(x);
|
||||||
|
axisDTO.setY(y);
|
||||||
|
receiveDTO.getChart().setAxis(axisDTO);
|
||||||
|
} else if (StringUtils.equalsIgnoreCase(receiveDTO.getChart().getType(), "table")) {
|
||||||
|
// 将fields赋值给columns
|
||||||
|
if (ObjectUtils.isEmpty(receiveDTO.getChart().getColumns())) {
|
||||||
|
List<AxisFieldDTO> columns = new ArrayList<>();
|
||||||
|
for (TableField field : fields) {
|
||||||
|
AxisFieldDTO dto = new AxisFieldDTO();
|
||||||
|
dto.setName(field.getOriginName());
|
||||||
|
dto.setValue(field.getOriginName());
|
||||||
|
columns.add(dto);
|
||||||
|
}
|
||||||
|
receiveDTO.getChart().setColumns(columns);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 所有图表都加上columns字段用于切换明细表展示
|
||||||
|
if (Arrays.asList(chartType).contains(receiveDTO.getChart().getType())) {
|
||||||
|
List<AxisFieldDTO> columns = new ArrayList<>();
|
||||||
|
columns.add(receiveDTO.getChart().getAxis().getX());
|
||||||
|
columns.add(receiveDTO.getChart().getAxis().getY());
|
||||||
|
receiveDTO.getChart().setColumns(columns);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<MsgDTO> getList(Long userId) {
|
||||||
|
MsgDTO lastMsg = msgManage.getLastMsg(userId);
|
||||||
|
if (lastMsg == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
List<MsgDTO> msg = msgManage.getMsg(lastMsg);
|
||||||
|
msgManage.deleteMsg(lastMsg);
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearAll(Long userId) {
|
||||||
|
msgManage.clearAllUserMsg(userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MsgDTO errorMsg(MsgDTO msgDTO, String errMsg) throws Exception {
|
||||||
|
// 如果异常,则获取最后一条成功的history
|
||||||
|
MsgDTO lastSuccessMsg = msgManage.getLastSuccessMsg(AuthUtils.getUser().getUserId(), msgDTO.getDatasetGroupId());
|
||||||
|
MsgDTO dto = new MsgDTO();
|
||||||
|
dto.setDatasetGroupId(msgDTO.getDatasetGroupId());
|
||||||
|
dto.setHistory(lastSuccessMsg == null ? new ArrayList<>() : lastSuccessMsg.getHistory());
|
||||||
|
dto.setMsgStatus(0);
|
||||||
|
dto.setMsgType("api");
|
||||||
|
dto.setErrMsg(errMsg);
|
||||||
|
msgManage.save(dto);
|
||||||
|
return dto;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<TableField> transField(List<TableField> fields) {
|
||||||
|
fields.forEach(field -> {
|
||||||
|
field.setDeExtractType(FieldUtils.transType2DeType(field.getFieldType()));
|
||||||
|
field.setDeType(FieldUtils.transType2DeType(field.getFieldType()));
|
||||||
|
});
|
||||||
|
return fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, Object> buildPreviewData(Map<String, Object> data, List<TableField> fields, Map<String, ColumnPermissionItem> desensitizationList) {
|
||||||
|
Map<String, Object> map = new LinkedHashMap<>();
|
||||||
|
List<String[]> dataList = (List<String[]>) data.get("data");
|
||||||
|
List<LinkedHashMap<String, Object>> dataObjectList = new ArrayList<>();
|
||||||
|
if (ObjectUtils.isNotEmpty(dataList)) {
|
||||||
|
for (int i = 0; i < dataList.size(); i++) {
|
||||||
|
String[] row = dataList.get(i);
|
||||||
|
LinkedHashMap<String, Object> obj = new LinkedHashMap<>();
|
||||||
|
if (row.length > 0) {
|
||||||
|
for (int j = 0; j < fields.size(); j++) {
|
||||||
|
TableField tableField = fields.get(j);
|
||||||
|
if (desensitizationList.containsKey(tableField.getOriginName())) {
|
||||||
|
obj.put(tableField.getOriginName(), ChartDataBuild.desensitizationValue(desensitizationList.get(tableField.getOriginName()), String.valueOf(row[j])));
|
||||||
|
} else {
|
||||||
|
if (tableField.getDeExtractType() == DeTypeConstants.DE_INT
|
||||||
|
|| tableField.getDeExtractType() == DeTypeConstants.DE_FLOAT
|
||||||
|
|| tableField.getDeExtractType() == DeTypeConstants.DE_BOOL) {
|
||||||
|
try {
|
||||||
|
obj.put(tableField.getOriginName(), new BigDecimal(row[j]));
|
||||||
|
} catch (Exception e) {
|
||||||
|
obj.put(tableField.getOriginName(), row[j]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
obj.put(tableField.getOriginName(), row[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dataObjectList.add(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
map.put("fields", fields);
|
||||||
|
map.put("data", dataObjectList);
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> transCreateTableFields(List<DatasetTableFieldDTO> allFields) {
|
||||||
|
List<String> list = new ArrayList<>();
|
||||||
|
for (DatasetTableFieldDTO dto : allFields) {
|
||||||
|
list.add(" " + dto.getDataeaseName() + " " + transNum2Type(dto.getDeExtractType()) +
|
||||||
|
" COMMENT '" + dto.getName() + "'");
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String transNum2Type(Integer num) {
|
||||||
|
return switch (num) {
|
||||||
|
case 0, 1, 5 -> "VARCHAR(50)";
|
||||||
|
case 2, 3, 4 -> "INT(10)";
|
||||||
|
default -> "VARCHAR(50)";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public Lex getLex(String type) {
|
||||||
|
switch (type) {
|
||||||
|
case "oracle":
|
||||||
|
return Lex.ORACLE;
|
||||||
|
case "sqlServer":
|
||||||
|
case "mssql":
|
||||||
|
return Lex.SQL_SERVER;
|
||||||
|
default:
|
||||||
|
return Lex.JAVA;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String transSql(String type, String copilotSQL, Provider provider, ReceiveDTO receiveDTO) {
|
||||||
|
if (type.equals("oracle") || type.equals("sqlServer")) {
|
||||||
|
try {
|
||||||
|
copilotSQL = copilotSQL.trim();
|
||||||
|
if (copilotSQL.endsWith(";")) {
|
||||||
|
copilotSQL = copilotSQL.substring(0, copilotSQL.length() - 1);
|
||||||
|
}
|
||||||
|
DatasourceSchemaDTO datasourceSchemaDTO = new DatasourceSchemaDTO();
|
||||||
|
datasourceSchemaDTO.setType(type);
|
||||||
|
SqlDialect dialect = provider.getDialect(datasourceSchemaDTO);
|
||||||
|
|
||||||
|
SqlParser parser = SqlParser.create(copilotSQL, SqlParser.Config.DEFAULT.withLex(getLex(type)));
|
||||||
|
SqlNode sqlNode = parser.parseStmt();
|
||||||
|
return sqlNode.toSqlString(dialect).toString().toLowerCase();
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.debug("calcite trans copilot SQL error");
|
||||||
|
return receiveDTO.getSql();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return copilotSQL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String engine(String type) {
|
||||||
|
switch (type) {
|
||||||
|
case "ck":
|
||||||
|
return "ClickHouse";
|
||||||
|
case "pg":
|
||||||
|
return "PostgreSQL";
|
||||||
|
case "mysql":
|
||||||
|
return "MySQL";
|
||||||
|
case "sqlServer":
|
||||||
|
return "SQL Server";
|
||||||
|
default:
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,100 @@
|
|||||||
|
package io.dataease.copilot.manage;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import io.dataease.api.copilot.dto.ChartDTO;
|
||||||
|
import io.dataease.api.copilot.dto.HistoryDTO;
|
||||||
|
import io.dataease.api.copilot.dto.MsgDTO;
|
||||||
|
import io.dataease.copilot.dao.auto.entity.CoreCopilotMsg;
|
||||||
|
import io.dataease.copilot.dao.auto.mapper.CoreCopilotMsgMapper;
|
||||||
|
import io.dataease.utils.AuthUtils;
|
||||||
|
import io.dataease.utils.BeanUtils;
|
||||||
|
import io.dataease.utils.IDUtils;
|
||||||
|
import io.dataease.utils.JsonUtil;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author Junjun
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class MsgManage {
|
||||||
|
@Resource
|
||||||
|
private CoreCopilotMsgMapper coreCopilotMsgMapper;
|
||||||
|
|
||||||
|
private ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
|
||||||
|
public void save(MsgDTO msgDTO) throws Exception {
|
||||||
|
msgDTO.setId(IDUtils.snowID());
|
||||||
|
msgDTO.setCreateTime(System.currentTimeMillis());
|
||||||
|
msgDTO.setUserId(AuthUtils.getUser().getUserId());
|
||||||
|
coreCopilotMsgMapper.insert(transDTO(msgDTO));
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<MsgDTO> getMsg(MsgDTO msgDTO) {
|
||||||
|
QueryWrapper<CoreCopilotMsg> wrapper = new QueryWrapper<>();
|
||||||
|
wrapper.eq("user_id", msgDTO.getUserId());
|
||||||
|
wrapper.eq("dataset_group_id", msgDTO.getDatasetGroupId());
|
||||||
|
wrapper.orderByAsc("create_time");
|
||||||
|
List<CoreCopilotMsg> perCopilotMsgs = coreCopilotMsgMapper.selectList(wrapper);
|
||||||
|
return perCopilotMsgs.stream().map(this::transRecord).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deleteMsg(MsgDTO msgDTO) {
|
||||||
|
QueryWrapper<CoreCopilotMsg> wrapper = new QueryWrapper<>();
|
||||||
|
wrapper.eq("user_id", msgDTO.getUserId());
|
||||||
|
wrapper.ne("dataset_group_id", msgDTO.getDatasetGroupId());
|
||||||
|
coreCopilotMsgMapper.delete(wrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearAllUserMsg(Long userId) {
|
||||||
|
QueryWrapper<CoreCopilotMsg> wrapper = new QueryWrapper<>();
|
||||||
|
wrapper.eq("user_id", userId);
|
||||||
|
coreCopilotMsgMapper.delete(wrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MsgDTO getLastMsg(Long userId) {
|
||||||
|
QueryWrapper<CoreCopilotMsg> wrapper = new QueryWrapper<>();
|
||||||
|
wrapper.eq("user_id", userId);
|
||||||
|
wrapper.orderByDesc("create_time");
|
||||||
|
List<CoreCopilotMsg> perCopilotMsgs = coreCopilotMsgMapper.selectList(wrapper);
|
||||||
|
return ObjectUtils.isEmpty(perCopilotMsgs) ? null : transRecord(perCopilotMsgs.getFirst());
|
||||||
|
}
|
||||||
|
|
||||||
|
public MsgDTO getLastSuccessMsg(Long userId, Long datasetGroupId) {
|
||||||
|
QueryWrapper<CoreCopilotMsg> wrapper = new QueryWrapper<>();
|
||||||
|
wrapper.eq("user_id", userId);
|
||||||
|
wrapper.eq("dataset_group_id", datasetGroupId);
|
||||||
|
wrapper.eq("msg_status", 1);
|
||||||
|
wrapper.eq("msg_type", "api");
|
||||||
|
wrapper.orderByDesc("create_time");
|
||||||
|
List<CoreCopilotMsg> perCopilotMsgs = coreCopilotMsgMapper.selectList(wrapper);
|
||||||
|
return ObjectUtils.isEmpty(perCopilotMsgs) ? null : transRecord(perCopilotMsgs.getFirst());
|
||||||
|
}
|
||||||
|
|
||||||
|
private CoreCopilotMsg transDTO(MsgDTO dto) throws Exception {
|
||||||
|
CoreCopilotMsg record = new CoreCopilotMsg();
|
||||||
|
BeanUtils.copyBean(record, dto);
|
||||||
|
record.setHistory(dto.getHistory() == null ? null : objectMapper.writeValueAsString(dto.getHistory()));
|
||||||
|
record.setChart(dto.getChart() == null ? null : objectMapper.writeValueAsString(dto.getChart()));
|
||||||
|
record.setChartData(dto.getChartData() == null ? null : objectMapper.writeValueAsString(dto.getChartData()));
|
||||||
|
return record;
|
||||||
|
}
|
||||||
|
|
||||||
|
private MsgDTO transRecord(CoreCopilotMsg record) {
|
||||||
|
MsgDTO dto = new MsgDTO();
|
||||||
|
BeanUtils.copyBean(dto, record);
|
||||||
|
TypeReference<List<HistoryDTO>> tokenType = new TypeReference<>() {
|
||||||
|
};
|
||||||
|
dto.setHistory(record.getHistory() == null ? new ArrayList<>() : JsonUtil.parseList(record.getHistory(), tokenType));
|
||||||
|
dto.setChart(record.getChart() == null ? null : JsonUtil.parseObject(record.getChart(), ChartDTO.class));
|
||||||
|
dto.setChartData(record.getChartData() == null ? null : JsonUtil.parse(record.getChartData(), Map.class));
|
||||||
|
return dto;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
package io.dataease.copilot.manage;
|
||||||
|
|
||||||
|
import io.dataease.api.copilot.dto.TokenDTO;
|
||||||
|
import io.dataease.copilot.dao.auto.entity.CoreCopilotToken;
|
||||||
|
import io.dataease.copilot.dao.auto.mapper.CoreCopilotTokenMapper;
|
||||||
|
import io.dataease.utils.BeanUtils;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author Junjun
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class TokenManage {
|
||||||
|
@Resource
|
||||||
|
private CoreCopilotTokenMapper coreCopilotTokenMapper;
|
||||||
|
|
||||||
|
public TokenDTO getToken(boolean valid) {
|
||||||
|
CoreCopilotToken perCopilotToken = coreCopilotTokenMapper.selectById(valid ? 2 : 1);
|
||||||
|
return transRecord(perCopilotToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateToken(String token, boolean valid) {
|
||||||
|
CoreCopilotToken record = new CoreCopilotToken();
|
||||||
|
record.setId(valid ? 2L : 1L);
|
||||||
|
record.setToken(token);
|
||||||
|
record.setUpdateTime(System.currentTimeMillis());
|
||||||
|
coreCopilotTokenMapper.updateById(record);
|
||||||
|
}
|
||||||
|
|
||||||
|
private TokenDTO transRecord(CoreCopilotToken perCopilotToken) {
|
||||||
|
TokenDTO dto = new TokenDTO();
|
||||||
|
BeanUtils.copyBean(dto, perCopilotToken);
|
||||||
|
return dto;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
package io.dataease.copilot.service;
|
||||||
|
|
||||||
|
import io.dataease.api.copilot.CopilotApi;
|
||||||
|
import io.dataease.api.copilot.dto.MsgDTO;
|
||||||
|
import io.dataease.copilot.manage.CopilotManage;
|
||||||
|
import io.dataease.utils.AuthUtils;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author Junjun
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("copilot")
|
||||||
|
public class CopilotService implements CopilotApi {
|
||||||
|
@Resource
|
||||||
|
private CopilotManage copilotManage;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MsgDTO chat(MsgDTO msgDTO) throws Exception {
|
||||||
|
try {
|
||||||
|
return copilotManage.chat(msgDTO);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return copilotManage.errorMsg(msgDTO, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<MsgDTO> getList() throws Exception {
|
||||||
|
return copilotManage.getList(AuthUtils.getUser().getUserId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clearAll() throws Exception {
|
||||||
|
copilotManage.clearAll(AuthUtils.getUser().getUserId());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
package io.dataease.dataset.constant;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author Junjun
|
||||||
|
*/
|
||||||
|
public class DatasetTableType {
|
||||||
|
public static String DB = "db";
|
||||||
|
public static String SQL = "sql";
|
||||||
|
public static String Es = "es";
|
||||||
|
}
|
@ -0,0 +1,231 @@
|
|||||||
|
package io.dataease.dataset.dao.auto.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
*
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author fit2cloud
|
||||||
|
* @since 2023-08-28
|
||||||
|
*/
|
||||||
|
@TableName("core_dataset_group")
|
||||||
|
public class CoreDatasetGroup implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ID
|
||||||
|
*/
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 名称
|
||||||
|
*/
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 父级ID
|
||||||
|
*/
|
||||||
|
private Long pid;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前分组处于第几级
|
||||||
|
*/
|
||||||
|
private Integer level;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* node类型:folder or dataset
|
||||||
|
*/
|
||||||
|
private String nodeType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sql,union
|
||||||
|
*/
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 连接模式:0-直连,1-同步(包括excel、api等数据存在de中的表)
|
||||||
|
*/
|
||||||
|
private Integer mode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关联关系树
|
||||||
|
*/
|
||||||
|
private String info;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建人ID
|
||||||
|
*/
|
||||||
|
private String createBy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建时间
|
||||||
|
*/
|
||||||
|
private Long createTime;
|
||||||
|
|
||||||
|
private String qrtzInstance;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 同步状态
|
||||||
|
*/
|
||||||
|
private String syncStatus;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新人ID
|
||||||
|
*/
|
||||||
|
private String updateBy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 最后同步时间
|
||||||
|
*/
|
||||||
|
private Long lastUpdateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关联sql
|
||||||
|
*/
|
||||||
|
private String unionSql;
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getPid() {
|
||||||
|
return pid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPid(Long pid) {
|
||||||
|
this.pid = pid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getLevel() {
|
||||||
|
return level;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLevel(Integer level) {
|
||||||
|
this.level = level;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNodeType() {
|
||||||
|
return nodeType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNodeType(String nodeType) {
|
||||||
|
this.nodeType = nodeType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(String type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getMode() {
|
||||||
|
return mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMode(Integer mode) {
|
||||||
|
this.mode = mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getInfo() {
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInfo(String info) {
|
||||||
|
this.info = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCreateBy() {
|
||||||
|
return createBy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreateBy(String createBy) {
|
||||||
|
this.createBy = createBy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getCreateTime() {
|
||||||
|
return createTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreateTime(Long createTime) {
|
||||||
|
this.createTime = createTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getQrtzInstance() {
|
||||||
|
return qrtzInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setQrtzInstance(String qrtzInstance) {
|
||||||
|
this.qrtzInstance = qrtzInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSyncStatus() {
|
||||||
|
return syncStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSyncStatus(String syncStatus) {
|
||||||
|
this.syncStatus = syncStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUpdateBy() {
|
||||||
|
return updateBy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUpdateBy(String updateBy) {
|
||||||
|
this.updateBy = updateBy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getLastUpdateTime() {
|
||||||
|
return lastUpdateTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLastUpdateTime(Long lastUpdateTime) {
|
||||||
|
this.lastUpdateTime = lastUpdateTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUnionSql() {
|
||||||
|
return unionSql;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUnionSql(String unionSql) {
|
||||||
|
this.unionSql = unionSql;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "CoreDatasetGroup{" +
|
||||||
|
"id = " + id +
|
||||||
|
", name = " + name +
|
||||||
|
", pid = " + pid +
|
||||||
|
", level = " + level +
|
||||||
|
", nodeType = " + nodeType +
|
||||||
|
", type = " + type +
|
||||||
|
", mode = " + mode +
|
||||||
|
", info = " + info +
|
||||||
|
", createBy = " + createBy +
|
||||||
|
", createTime = " + createTime +
|
||||||
|
", qrtzInstance = " + qrtzInstance +
|
||||||
|
", syncStatus = " + syncStatus +
|
||||||
|
", updateBy = " + updateBy +
|
||||||
|
", lastUpdateTime = " + lastUpdateTime +
|
||||||
|
", unionSql = " + unionSql +
|
||||||
|
"}";
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,136 @@
|
|||||||
|
package io.dataease.dataset.dao.auto.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
*
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author fit2cloud
|
||||||
|
* @since 2023-04-14
|
||||||
|
*/
|
||||||
|
@TableName("core_dataset_table")
|
||||||
|
public class CoreDatasetTable implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ID
|
||||||
|
*/
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 名称
|
||||||
|
*/
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 物理表名
|
||||||
|
*/
|
||||||
|
private String tableName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数据源ID
|
||||||
|
*/
|
||||||
|
private Long datasourceId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数据集ID
|
||||||
|
*/
|
||||||
|
private Long datasetGroupId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* db,sql,union,excel,api
|
||||||
|
*/
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表原始信息,表名,sql等
|
||||||
|
*/
|
||||||
|
private String info;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SQL参数
|
||||||
|
*/
|
||||||
|
private String sqlVariableDetails;
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTableName() {
|
||||||
|
return tableName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTableName(String tableName) {
|
||||||
|
this.tableName = tableName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getDatasourceId() {
|
||||||
|
return datasourceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDatasourceId(Long datasourceId) {
|
||||||
|
this.datasourceId = datasourceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getDatasetGroupId() {
|
||||||
|
return datasetGroupId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDatasetGroupId(Long datasetGroupId) {
|
||||||
|
this.datasetGroupId = datasetGroupId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(String type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getInfo() {
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInfo(String info) {
|
||||||
|
this.info = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSqlVariableDetails() {
|
||||||
|
return sqlVariableDetails;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSqlVariableDetails(String sqlVariableDetails) {
|
||||||
|
this.sqlVariableDetails = sqlVariableDetails;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "CoreDatasetTable{" +
|
||||||
|
"id = " + id +
|
||||||
|
", name = " + name +
|
||||||
|
", tableName = " + tableName +
|
||||||
|
", datasourceId = " + datasourceId +
|
||||||
|
", datasetGroupId = " + datasetGroupId +
|
||||||
|
", type = " + type +
|
||||||
|
", info = " + info +
|
||||||
|
", sqlVariableDetails = " + sqlVariableDetails +
|
||||||
|
"}";
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,374 @@
|
|||||||
|
package io.dataease.dataset.dao.auto.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* table数据集表字段
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author fit2cloud
|
||||||
|
* @since 2025-02-06
|
||||||
|
*/
|
||||||
|
@TableName("core_dataset_table_field")
|
||||||
|
public class CoreDatasetTableField implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ID
|
||||||
|
*/
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数据源ID
|
||||||
|
*/
|
||||||
|
private Long datasourceId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数据表ID
|
||||||
|
*/
|
||||||
|
private Long datasetTableId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数据集ID
|
||||||
|
*/
|
||||||
|
private Long datasetGroupId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 视图ID
|
||||||
|
*/
|
||||||
|
private Long chartId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 原始字段名
|
||||||
|
*/
|
||||||
|
private String originName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字段名用于展示
|
||||||
|
*/
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 描述
|
||||||
|
*/
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* de字段名用作唯一标识
|
||||||
|
*/
|
||||||
|
private String dataeaseName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* de字段别名
|
||||||
|
*/
|
||||||
|
private String fieldShortName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分组设置
|
||||||
|
*/
|
||||||
|
private String groupList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 未分组的值
|
||||||
|
*/
|
||||||
|
private String otherGroup;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 维度/指标标识 d:维度,q:指标
|
||||||
|
*/
|
||||||
|
private String groupType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 原始字段类型
|
||||||
|
*/
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字段长度(允许为空,默认0)
|
||||||
|
*/
|
||||||
|
private Integer size;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dataease字段类型:0-文本,1-时间,2-整型数值,3-浮点数值,4-布尔,5-地理位置,6-二进制
|
||||||
|
*/
|
||||||
|
private Integer deType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* de记录的原始类型
|
||||||
|
*/
|
||||||
|
private Integer deExtractType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否扩展字段 0原始 1复制 2计算字段...
|
||||||
|
*/
|
||||||
|
private Integer extField;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否选中
|
||||||
|
*/
|
||||||
|
private Boolean checked;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 列位置
|
||||||
|
*/
|
||||||
|
private Integer columnIndex;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 同步时间
|
||||||
|
*/
|
||||||
|
private Long lastSyncTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 精度
|
||||||
|
*/
|
||||||
|
private Integer accuracy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 时间字段类型
|
||||||
|
*/
|
||||||
|
private String dateFormat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 时间格式类型
|
||||||
|
*/
|
||||||
|
private String dateFormatType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算字段参数
|
||||||
|
*/
|
||||||
|
private String params;
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getDatasourceId() {
|
||||||
|
return datasourceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDatasourceId(Long datasourceId) {
|
||||||
|
this.datasourceId = datasourceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getDatasetTableId() {
|
||||||
|
return datasetTableId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDatasetTableId(Long datasetTableId) {
|
||||||
|
this.datasetTableId = datasetTableId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getDatasetGroupId() {
|
||||||
|
return datasetGroupId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDatasetGroupId(Long datasetGroupId) {
|
||||||
|
this.datasetGroupId = datasetGroupId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getChartId() {
|
||||||
|
return chartId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setChartId(Long chartId) {
|
||||||
|
this.chartId = chartId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getOriginName() {
|
||||||
|
return originName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOriginName(String originName) {
|
||||||
|
this.originName = originName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDescription(String description) {
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDataeaseName() {
|
||||||
|
return dataeaseName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDataeaseName(String dataeaseName) {
|
||||||
|
this.dataeaseName = dataeaseName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFieldShortName() {
|
||||||
|
return fieldShortName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFieldShortName(String fieldShortName) {
|
||||||
|
this.fieldShortName = fieldShortName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getGroupList() {
|
||||||
|
return groupList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGroupList(String groupList) {
|
||||||
|
this.groupList = groupList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getOtherGroup() {
|
||||||
|
return otherGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOtherGroup(String otherGroup) {
|
||||||
|
this.otherGroup = otherGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getGroupType() {
|
||||||
|
return groupType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGroupType(String groupType) {
|
||||||
|
this.groupType = groupType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(String type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getSize() {
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSize(Integer size) {
|
||||||
|
this.size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getDeType() {
|
||||||
|
return deType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeType(Integer deType) {
|
||||||
|
this.deType = deType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getDeExtractType() {
|
||||||
|
return deExtractType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeExtractType(Integer deExtractType) {
|
||||||
|
this.deExtractType = deExtractType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getExtField() {
|
||||||
|
return extField;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExtField(Integer extField) {
|
||||||
|
this.extField = extField;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getChecked() {
|
||||||
|
return checked;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setChecked(Boolean checked) {
|
||||||
|
this.checked = checked;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getColumnIndex() {
|
||||||
|
return columnIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setColumnIndex(Integer columnIndex) {
|
||||||
|
this.columnIndex = columnIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getLastSyncTime() {
|
||||||
|
return lastSyncTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLastSyncTime(Long lastSyncTime) {
|
||||||
|
this.lastSyncTime = lastSyncTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getAccuracy() {
|
||||||
|
return accuracy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAccuracy(Integer accuracy) {
|
||||||
|
this.accuracy = accuracy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDateFormat() {
|
||||||
|
return dateFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDateFormat(String dateFormat) {
|
||||||
|
this.dateFormat = dateFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDateFormatType() {
|
||||||
|
return dateFormatType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDateFormatType(String dateFormatType) {
|
||||||
|
this.dateFormatType = dateFormatType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getParams() {
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setParams(String params) {
|
||||||
|
this.params = params;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "CoreDatasetTableField{" +
|
||||||
|
"id = " + id +
|
||||||
|
", datasourceId = " + datasourceId +
|
||||||
|
", datasetTableId = " + datasetTableId +
|
||||||
|
", datasetGroupId = " + datasetGroupId +
|
||||||
|
", chartId = " + chartId +
|
||||||
|
", originName = " + originName +
|
||||||
|
", name = " + name +
|
||||||
|
", description = " + description +
|
||||||
|
", dataeaseName = " + dataeaseName +
|
||||||
|
", fieldShortName = " + fieldShortName +
|
||||||
|
", groupList = " + groupList +
|
||||||
|
", otherGroup = " + otherGroup +
|
||||||
|
", groupType = " + groupType +
|
||||||
|
", type = " + type +
|
||||||
|
", size = " + size +
|
||||||
|
", deType = " + deType +
|
||||||
|
", deExtractType = " + deExtractType +
|
||||||
|
", extField = " + extField +
|
||||||
|
", checked = " + checked +
|
||||||
|
", columnIndex = " + columnIndex +
|
||||||
|
", lastSyncTime = " + lastSyncTime +
|
||||||
|
", accuracy = " + accuracy +
|
||||||
|
", dateFormat = " + dateFormat +
|
||||||
|
", dateFormatType = " + dateFormatType +
|
||||||
|
", params = " + params +
|
||||||
|
"}";
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,122 @@
|
|||||||
|
package io.dataease.dataset.dao.auto.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
*
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author fit2cloud
|
||||||
|
* @since 2023-08-08
|
||||||
|
*/
|
||||||
|
@TableName("core_dataset_table_sql_log")
|
||||||
|
public class CoreDatasetTableSqlLog implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ID
|
||||||
|
*/
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数据集SQL节点ID
|
||||||
|
*/
|
||||||
|
private String tableId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开始时间
|
||||||
|
*/
|
||||||
|
private Long startTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 结束时间
|
||||||
|
*/
|
||||||
|
private Long endTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 耗时(毫秒)
|
||||||
|
*/
|
||||||
|
private Long spend;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 详细信息
|
||||||
|
*/
|
||||||
|
private String sql;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态
|
||||||
|
*/
|
||||||
|
private String status;
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(String id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTableId() {
|
||||||
|
return tableId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTableId(String tableId) {
|
||||||
|
this.tableId = tableId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getStartTime() {
|
||||||
|
return startTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStartTime(Long startTime) {
|
||||||
|
this.startTime = startTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getEndTime() {
|
||||||
|
return endTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEndTime(Long endTime) {
|
||||||
|
this.endTime = endTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getSpend() {
|
||||||
|
return spend;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSpend(Long spend) {
|
||||||
|
this.spend = spend;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSql() {
|
||||||
|
return sql;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSql(String sql) {
|
||||||
|
this.sql = sql;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatus(String status) {
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "CoreDatasetTableSqlLog{" +
|
||||||
|
"id = " + id +
|
||||||
|
", tableId = " + tableId +
|
||||||
|
", startTime = " + startTime +
|
||||||
|
", endTime = " + endTime +
|
||||||
|
", spend = " + spend +
|
||||||
|
", sql = " + sql +
|
||||||
|
", status = " + status +
|
||||||
|
"}";
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package io.dataease.dataset.dao.auto.mapper;
|
||||||
|
|
||||||
|
import io.dataease.dataset.dao.auto.entity.CoreDatasetGroup;
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Mapper 接口
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author fit2cloud
|
||||||
|
* @since 2023-08-28
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface CoreDatasetGroupMapper extends BaseMapper<CoreDatasetGroup> {
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package io.dataease.dataset.dao.auto.mapper;
|
||||||
|
|
||||||
|
import io.dataease.dataset.dao.auto.entity.CoreDatasetTableField;
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* table数据集表字段 Mapper 接口
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author fit2cloud
|
||||||
|
* @since 2025-02-06
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface CoreDatasetTableFieldMapper extends BaseMapper<CoreDatasetTableField> {
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package io.dataease.dataset.dao.auto.mapper;
|
||||||
|
|
||||||
|
import io.dataease.dataset.dao.auto.entity.CoreDatasetTable;
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Mapper 接口
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author fit2cloud
|
||||||
|
* @since 2023-04-14
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface CoreDatasetTableMapper extends BaseMapper<CoreDatasetTable> {
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package io.dataease.dataset.dao.auto.mapper;
|
||||||
|
|
||||||
|
import io.dataease.dataset.dao.auto.entity.CoreDatasetTableSqlLog;
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Mapper 接口
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author fit2cloud
|
||||||
|
* @since 2023-08-08
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface CoreDatasetTableSqlLogMapper extends BaseMapper<CoreDatasetTableSqlLog> {
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
package io.dataease.dataset.dao.ext.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
import io.dataease.api.dataset.vo.DataSetBarVO;
|
||||||
|
import io.dataease.dataset.dao.ext.po.DataSetNodePO;
|
||||||
|
import io.dataease.model.BusiNodeRequest;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
import org.apache.ibatis.annotations.Select;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface CoreDataSetExtMapper {
|
||||||
|
|
||||||
|
@Select("""
|
||||||
|
select id, name, node_type, pid from core_dataset_group
|
||||||
|
${ew.customSqlSegment}
|
||||||
|
""")
|
||||||
|
List<DataSetNodePO> query(@Param("ew") QueryWrapper queryWrapper);
|
||||||
|
|
||||||
|
@Select("select id, name, node_type, create_by, create_time, update_by, last_update_time from core_dataset_group where id = #{id}")
|
||||||
|
DataSetBarVO queryBarInfo(@Param("id") Long id);
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
package io.dataease.dataset.dao.ext.po;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class DataSetNodePO implements Serializable {
|
||||||
|
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = -4457506330575500164L;
|
||||||
|
|
||||||
|
private Long id;
|
||||||
|
private String name;
|
||||||
|
private String nodeType;
|
||||||
|
private Long pid;
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
package io.dataease.dataset.dto;
|
||||||
|
|
||||||
|
import io.dataease.model.TreeBaseModel;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class DataSetNodeBO implements TreeBaseModel {
|
||||||
|
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 728340676442387790L;
|
||||||
|
|
||||||
|
private Long id;
|
||||||
|
private String name;
|
||||||
|
private Boolean leaf;
|
||||||
|
private Integer weight = 3;
|
||||||
|
private Long pid;
|
||||||
|
private Integer extraFlag;
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,605 @@
|
|||||||
|
package io.dataease.dataset.manage;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
|
import io.dataease.api.dataset.union.DatasetGroupInfoDTO;
|
||||||
|
import io.dataease.api.dataset.union.UnionDTO;
|
||||||
|
import io.dataease.api.dataset.vo.DataSetBarVO;
|
||||||
|
import io.dataease.api.permissions.relation.api.RelationApi;
|
||||||
|
import io.dataease.commons.constants.OptConstants;
|
||||||
|
import io.dataease.dataset.dao.auto.entity.CoreDatasetGroup;
|
||||||
|
import io.dataease.dataset.dao.auto.entity.CoreDatasetTable;
|
||||||
|
import io.dataease.dataset.dao.auto.mapper.CoreDatasetGroupMapper;
|
||||||
|
import io.dataease.dataset.dao.auto.mapper.CoreDatasetTableMapper;
|
||||||
|
import io.dataease.dataset.dao.ext.mapper.CoreDataSetExtMapper;
|
||||||
|
import io.dataease.dataset.dao.ext.po.DataSetNodePO;
|
||||||
|
import io.dataease.dataset.dto.DataSetNodeBO;
|
||||||
|
import io.dataease.dataset.utils.FieldUtils;
|
||||||
|
import io.dataease.dataset.utils.TableUtils;
|
||||||
|
import io.dataease.datasource.dao.auto.entity.CoreDatasource;
|
||||||
|
import io.dataease.datasource.dao.auto.mapper.CoreDatasourceMapper;
|
||||||
|
import io.dataease.engine.constant.ExtFieldConstant;
|
||||||
|
import io.dataease.exception.DEException;
|
||||||
|
import io.dataease.extensions.datasource.dto.DatasetTableDTO;
|
||||||
|
import io.dataease.extensions.datasource.dto.DatasetTableFieldDTO;
|
||||||
|
import io.dataease.extensions.datasource.dto.DatasourceDTO;
|
||||||
|
import io.dataease.extensions.view.dto.SqlVariableDetails;
|
||||||
|
import io.dataease.i18n.Translator;
|
||||||
|
import io.dataease.license.config.XpackInteract;
|
||||||
|
import io.dataease.license.utils.LicenseUtil;
|
||||||
|
import io.dataease.model.BusiNodeRequest;
|
||||||
|
import io.dataease.model.BusiNodeVO;
|
||||||
|
import io.dataease.operation.manage.CoreOptRecentManage;
|
||||||
|
import io.dataease.system.manage.CoreUserManage;
|
||||||
|
import io.dataease.utils.*;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.locks.Lock;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author Junjun
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public class DatasetGroupManage {
|
||||||
|
@Resource
|
||||||
|
private CoreDatasetGroupMapper coreDatasetGroupMapper;
|
||||||
|
@Resource
|
||||||
|
private DatasetSQLManage datasetSQLManage;
|
||||||
|
@Resource
|
||||||
|
private DatasetDataManage datasetDataManage;
|
||||||
|
@Resource
|
||||||
|
private DatasetTableManage datasetTableManage;
|
||||||
|
@Resource
|
||||||
|
private DatasetTableFieldManage datasetTableFieldManage;
|
||||||
|
@Resource
|
||||||
|
private PermissionManage permissionManage;
|
||||||
|
@Resource
|
||||||
|
private CoreDataSetExtMapper coreDataSetExtMapper;
|
||||||
|
@Resource
|
||||||
|
private CoreDatasetTableMapper coreDatasetTableMapper;
|
||||||
|
@Resource
|
||||||
|
private CoreDatasourceMapper coreDatasourceMapper;
|
||||||
|
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private CoreUserManage coreUserManage;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private CoreOptRecentManage coreOptRecentManage;
|
||||||
|
|
||||||
|
@Autowired(required = false)
|
||||||
|
private RelationApi relationManage;
|
||||||
|
|
||||||
|
private static final String leafType = "dataset";
|
||||||
|
|
||||||
|
private Lock lock = new ReentrantLock();
|
||||||
|
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public DatasetGroupInfoDTO save(DatasetGroupInfoDTO datasetGroupInfoDTO, boolean rename) throws Exception {
|
||||||
|
lock.lock();
|
||||||
|
try {
|
||||||
|
boolean isCreate;
|
||||||
|
// 用于重命名获取pid
|
||||||
|
if (ObjectUtils.isEmpty(datasetGroupInfoDTO.getPid()) && ObjectUtils.isNotEmpty(datasetGroupInfoDTO.getId())) {
|
||||||
|
CoreDatasetGroup coreDatasetGroup = coreDatasetGroupMapper.selectById(datasetGroupInfoDTO.getId());
|
||||||
|
datasetGroupInfoDTO.setPid(coreDatasetGroup.getPid());
|
||||||
|
}
|
||||||
|
datasetGroupInfoDTO.setUpdateBy(AuthUtils.getUser().getUserId() + "");
|
||||||
|
datasetGroupInfoDTO.setLastUpdateTime(System.currentTimeMillis());
|
||||||
|
if (StringUtils.equalsIgnoreCase(datasetGroupInfoDTO.getNodeType(), leafType)) {
|
||||||
|
if (!rename && ObjectUtils.isEmpty(datasetGroupInfoDTO.getAllFields())) {
|
||||||
|
DEException.throwException(Translator.get("i18n_no_fields"));
|
||||||
|
}
|
||||||
|
// get union sql
|
||||||
|
Map<String, Object> sqlMap = datasetSQLManage.getUnionSQLForEdit(datasetGroupInfoDTO, null);
|
||||||
|
if (ObjectUtils.isNotEmpty(sqlMap)) {
|
||||||
|
String sql = (String) sqlMap.get("sql");
|
||||||
|
datasetGroupInfoDTO.setUnionSql(sql);
|
||||||
|
datasetGroupInfoDTO.setInfo(Objects.requireNonNull(JsonUtil.toJSONString(datasetGroupInfoDTO.getUnion())).toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// save dataset/group
|
||||||
|
long time = System.currentTimeMillis();
|
||||||
|
if (ObjectUtils.isEmpty(datasetGroupInfoDTO.getId())) {
|
||||||
|
isCreate = true;
|
||||||
|
datasetGroupInfoDTO.setId(IDUtils.snowID());
|
||||||
|
datasetGroupInfoDTO.setCreateBy(AuthUtils.getUser().getUserId() + "");
|
||||||
|
datasetGroupInfoDTO.setUpdateBy(AuthUtils.getUser().getUserId() + "");
|
||||||
|
datasetGroupInfoDTO.setCreateTime(time);
|
||||||
|
datasetGroupInfoDTO.setLastUpdateTime(time);
|
||||||
|
datasetGroupInfoDTO.setPid(datasetGroupInfoDTO.getPid() == null ? 0L : datasetGroupInfoDTO.getPid());
|
||||||
|
Objects.requireNonNull(CommonBeanFactory.getBean(this.getClass())).innerSave(datasetGroupInfoDTO);
|
||||||
|
} else {
|
||||||
|
isCreate = false;
|
||||||
|
if (Objects.equals(datasetGroupInfoDTO.getId(), datasetGroupInfoDTO.getPid())) {
|
||||||
|
DEException.throwException(Translator.get("i18n_pid_not_eq_id"));
|
||||||
|
}
|
||||||
|
Objects.requireNonNull(CommonBeanFactory.getBean(this.getClass())).innerEdit(datasetGroupInfoDTO);
|
||||||
|
}
|
||||||
|
// node_type=dataset需要创建dataset_table和field
|
||||||
|
if (StringUtils.equalsIgnoreCase(datasetGroupInfoDTO.getNodeType(), "dataset")) {
|
||||||
|
List<Long> tableIds = new ArrayList<>();
|
||||||
|
List<Long> fieldIds = new ArrayList<>();
|
||||||
|
// 解析tree,保存
|
||||||
|
saveTable(datasetGroupInfoDTO, datasetGroupInfoDTO.getUnion(), tableIds, isCreate);
|
||||||
|
saveField(datasetGroupInfoDTO, fieldIds);
|
||||||
|
// 删除不要的table和field
|
||||||
|
datasetTableManage.deleteByDatasetGroupUpdate(datasetGroupInfoDTO.getId(), tableIds);
|
||||||
|
datasetTableFieldManage.deleteByDatasetGroupUpdate(datasetGroupInfoDTO.getId(), fieldIds);
|
||||||
|
}
|
||||||
|
return datasetGroupInfoDTO;
|
||||||
|
} catch (Exception e) {
|
||||||
|
DEException.throwException(e.getMessage());
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@XpackInteract(value = "authResourceTree", before = false)
|
||||||
|
public void innerEdit(DatasetGroupInfoDTO datasetGroupInfoDTO) {
|
||||||
|
checkName(datasetGroupInfoDTO);
|
||||||
|
CoreDatasetGroup coreDatasetGroup = BeanUtils.copyBean(new CoreDatasetGroup(), datasetGroupInfoDTO);
|
||||||
|
coreDatasetGroup.setLastUpdateTime(System.currentTimeMillis());
|
||||||
|
coreDatasetGroupMapper.updateById(coreDatasetGroup);
|
||||||
|
coreOptRecentManage.saveOpt(datasetGroupInfoDTO.getId(), OptConstants.OPT_RESOURCE_TYPE.DATASET, OptConstants.OPT_TYPE.UPDATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@XpackInteract(value = "authResourceTree", before = false)
|
||||||
|
public void innerSave(DatasetGroupInfoDTO datasetGroupInfoDTO) {
|
||||||
|
checkName(datasetGroupInfoDTO);
|
||||||
|
CoreDatasetGroup coreDatasetGroup = BeanUtils.copyBean(new CoreDatasetGroup(), datasetGroupInfoDTO);
|
||||||
|
coreDatasetGroupMapper.insert(coreDatasetGroup);
|
||||||
|
coreOptRecentManage.saveOpt(coreDatasetGroup.getId(), OptConstants.OPT_RESOURCE_TYPE.DATASET, OptConstants.OPT_TYPE.NEW);
|
||||||
|
}
|
||||||
|
|
||||||
|
@XpackInteract(value = "authResourceTree", before = false)
|
||||||
|
public DatasetGroupInfoDTO move(DatasetGroupInfoDTO datasetGroupInfoDTO) {
|
||||||
|
checkName(datasetGroupInfoDTO);
|
||||||
|
if (datasetGroupInfoDTO.getPid() != 0) {
|
||||||
|
checkMove(datasetGroupInfoDTO);
|
||||||
|
}
|
||||||
|
// save dataset/group
|
||||||
|
long time = System.currentTimeMillis();
|
||||||
|
CoreDatasetGroup coreDatasetGroup = new CoreDatasetGroup();
|
||||||
|
BeanUtils.copyBean(coreDatasetGroup, datasetGroupInfoDTO);
|
||||||
|
datasetGroupInfoDTO.setUpdateBy(AuthUtils.getUser().getUserId() + "");
|
||||||
|
coreDatasetGroup.setLastUpdateTime(time);
|
||||||
|
coreDatasetGroupMapper.updateById(coreDatasetGroup);
|
||||||
|
coreOptRecentManage.saveOpt(coreDatasetGroup.getId(), OptConstants.OPT_RESOURCE_TYPE.DATASET, OptConstants.OPT_TYPE.UPDATE);
|
||||||
|
return datasetGroupInfoDTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean perDelete(Long id) {
|
||||||
|
if (LicenseUtil.licenseValid()) {
|
||||||
|
try {
|
||||||
|
relationManage.checkAuth();
|
||||||
|
} catch (Exception e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Long count = relationManage.getDatasetResource(id);
|
||||||
|
if (count > 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@XpackInteract(value = "authResourceTree", before = false)
|
||||||
|
public void delete(Long id) {
|
||||||
|
CoreDatasetGroup coreDatasetGroup = coreDatasetGroupMapper.selectById(id);
|
||||||
|
if (ObjectUtils.isEmpty(coreDatasetGroup)) {
|
||||||
|
DEException.throwException("resource not exist");
|
||||||
|
}
|
||||||
|
Objects.requireNonNull(CommonBeanFactory.getBean(this.getClass())).recursionDel(id);
|
||||||
|
coreOptRecentManage.saveOpt(coreDatasetGroup.getId(), OptConstants.OPT_RESOURCE_TYPE.DATASET, OptConstants.OPT_TYPE.DELETE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void recursionDel(Long id) {
|
||||||
|
coreDatasetGroupMapper.deleteById(id);
|
||||||
|
datasetTableManage.deleteByDatasetGroupDelete(id);
|
||||||
|
datasetTableFieldManage.deleteByDatasetGroupDelete(id);
|
||||||
|
|
||||||
|
QueryWrapper<CoreDatasetGroup> wrapper = new QueryWrapper<>();
|
||||||
|
wrapper.eq("pid", id);
|
||||||
|
List<CoreDatasetGroup> coreDatasetGroups = coreDatasetGroupMapper.selectList(wrapper);
|
||||||
|
if (ObjectUtils.isNotEmpty(coreDatasetGroups)) {
|
||||||
|
for (CoreDatasetGroup record : coreDatasetGroups) {
|
||||||
|
recursionDel(record.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@XpackInteract(value = "authResourceTree", replace = true, invalid = true)
|
||||||
|
public List<BusiNodeVO> tree(BusiNodeRequest request) {
|
||||||
|
|
||||||
|
QueryWrapper<Object> queryWrapper = new QueryWrapper<>();
|
||||||
|
if (ObjectUtils.isNotEmpty(request.getLeaf())) {
|
||||||
|
queryWrapper.eq("node_type", request.getLeaf() ? "dataset" : "folder");
|
||||||
|
}
|
||||||
|
String info = CommunityUtils.getInfo();
|
||||||
|
if (StringUtils.isNotBlank(info)) {
|
||||||
|
queryWrapper.notExists(String.format(info, "core_dataset_group.id"));
|
||||||
|
}
|
||||||
|
queryWrapper.orderByDesc("create_time");
|
||||||
|
List<DataSetNodePO> pos = coreDataSetExtMapper.query(queryWrapper);
|
||||||
|
List<DataSetNodeBO> nodes = new ArrayList<>();
|
||||||
|
if (ObjectUtils.isEmpty(request.getLeaf()) || !request.getLeaf()) nodes.add(rootNode());
|
||||||
|
List<DataSetNodeBO> bos = pos.stream().map(this::convert).toList();
|
||||||
|
if (CollectionUtils.isNotEmpty(bos)) {
|
||||||
|
nodes.addAll(bos);
|
||||||
|
}
|
||||||
|
return TreeUtils.mergeTree(nodes, BusiNodeVO.class, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DataSetBarVO queryBarInfo(Long id) {
|
||||||
|
DataSetBarVO dataSetBarVO = coreDataSetExtMapper.queryBarInfo(id);
|
||||||
|
// get creator
|
||||||
|
String userName = coreUserManage.getUserName(Long.valueOf(dataSetBarVO.getCreateBy()));
|
||||||
|
if (StringUtils.isNotBlank(userName)) {
|
||||||
|
dataSetBarVO.setCreator(userName);
|
||||||
|
}
|
||||||
|
String updateUserName = coreUserManage.getUserName(Long.valueOf(dataSetBarVO.getUpdateBy()));
|
||||||
|
if (StringUtils.isNotBlank(updateUserName)) {
|
||||||
|
dataSetBarVO.setUpdater(updateUserName);
|
||||||
|
}
|
||||||
|
dataSetBarVO.setDatasourceDTOList(getDatasource(id));
|
||||||
|
return dataSetBarVO;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<DatasourceDTO> getDatasource(Long datasetId) {
|
||||||
|
QueryWrapper<CoreDatasetTable> wrapper = new QueryWrapper<>();
|
||||||
|
wrapper.eq("dataset_group_id", datasetId);
|
||||||
|
List<CoreDatasetTable> coreDatasetTables = coreDatasetTableMapper.selectList(wrapper);
|
||||||
|
Set<Long> ids = new LinkedHashSet();
|
||||||
|
coreDatasetTables.forEach(ele -> ids.add(ele.getDatasourceId()));
|
||||||
|
if (CollectionUtils.isEmpty(ids)) {
|
||||||
|
DEException.throwException(Translator.get("i18n_dataset_create_error"));
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryWrapper<CoreDatasource> datasourceQueryWrapper = new QueryWrapper<>();
|
||||||
|
datasourceQueryWrapper.in("id", ids);
|
||||||
|
List<DatasourceDTO> datasourceDTOList = coreDatasourceMapper.selectList(datasourceQueryWrapper).stream().map(ele -> {
|
||||||
|
DatasourceDTO dto = new DatasourceDTO();
|
||||||
|
BeanUtils.copyBean(dto, ele);
|
||||||
|
dto.setConfiguration(null);
|
||||||
|
return dto;
|
||||||
|
}).collect(Collectors.toList());
|
||||||
|
if (ids.size() != datasourceDTOList.size()) {
|
||||||
|
DEException.throwException(Translator.get("i18n_dataset_ds_delete"));
|
||||||
|
}
|
||||||
|
return datasourceDTOList;
|
||||||
|
}
|
||||||
|
|
||||||
|
private DataSetNodeBO rootNode() {
|
||||||
|
return new DataSetNodeBO(0L, "root", false, 7, -1L, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private DataSetNodeBO convert(DataSetNodePO po) {
|
||||||
|
return new DataSetNodeBO(po.getId(), po.getName(), StringUtils.equals(po.getNodeType(), leafType), 9, po.getPid(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkName(DatasetGroupInfoDTO dto) {
|
||||||
|
if (!LicenseUtil.licenseValid()) {
|
||||||
|
QueryWrapper<CoreDatasetGroup> wrapper = new QueryWrapper<>();
|
||||||
|
if (ObjectUtils.isNotEmpty(dto.getPid())) {
|
||||||
|
wrapper.eq("pid", dto.getPid());
|
||||||
|
}
|
||||||
|
if (StringUtils.isNotEmpty(dto.getName())) {
|
||||||
|
wrapper.eq("name", dto.getName());
|
||||||
|
}
|
||||||
|
if (ObjectUtils.isNotEmpty(dto.getId())) {
|
||||||
|
wrapper.ne("id", dto.getId());
|
||||||
|
}
|
||||||
|
if (ObjectUtils.isNotEmpty(dto.getLevel())) {
|
||||||
|
wrapper.eq("level", dto.getLevel());
|
||||||
|
}
|
||||||
|
if (ObjectUtils.isNotEmpty(dto.getNodeType())) {
|
||||||
|
wrapper.eq("node_type", dto.getNodeType());
|
||||||
|
}
|
||||||
|
List<CoreDatasetGroup> list = coreDatasetGroupMapper.selectList(wrapper);
|
||||||
|
if (list.size() > 0) {
|
||||||
|
DEException.throwException(Translator.get("i18n_ds_name_exists"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void saveTable(DatasetGroupInfoDTO datasetGroupInfoDTO, List<UnionDTO> union, List<Long> tableIds, boolean isCreate) {
|
||||||
|
// table和field均由前端生成id(如果没有id)
|
||||||
|
Long datasetGroupId = datasetGroupInfoDTO.getId();
|
||||||
|
if (ObjectUtils.isNotEmpty(union)) {
|
||||||
|
for (UnionDTO unionDTO : union) {
|
||||||
|
DatasetTableDTO currentDs = unionDTO.getCurrentDs();
|
||||||
|
CoreDatasetTable coreDatasetTable = datasetTableManage.selectById(currentDs.getId());
|
||||||
|
if (coreDatasetTable != null && isCreate) {
|
||||||
|
DEException.throwException(Translator.get("i18n_table_duplicate"));
|
||||||
|
}
|
||||||
|
currentDs.setDatasetGroupId(datasetGroupId);
|
||||||
|
datasetTableManage.save(currentDs);
|
||||||
|
tableIds.add(currentDs.getId());
|
||||||
|
|
||||||
|
saveTable(datasetGroupInfoDTO, unionDTO.getChildrenDs(), tableIds, isCreate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void saveField(DatasetGroupInfoDTO datasetGroupInfoDTO, List<Long> fieldIds) throws Exception {
|
||||||
|
if (ObjectUtils.isEmpty(datasetGroupInfoDTO.getUnion())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
datasetDataManage.previewDataWithLimit(datasetGroupInfoDTO, 0, 1, false);
|
||||||
|
// table和field均由前端生成id(如果没有id)
|
||||||
|
Long datasetGroupId = datasetGroupInfoDTO.getId();
|
||||||
|
List<DatasetTableFieldDTO> allFields = datasetGroupInfoDTO.getAllFields();
|
||||||
|
if (ObjectUtils.isNotEmpty(allFields)) {
|
||||||
|
// 获取内层union sql和字段
|
||||||
|
Map<String, Object> map = datasetSQLManage.getUnionSQLForEdit(datasetGroupInfoDTO, null);
|
||||||
|
List<DatasetTableFieldDTO> unionFields = (List<DatasetTableFieldDTO>) map.get("field");
|
||||||
|
|
||||||
|
for (DatasetTableFieldDTO datasetTableFieldDTO : allFields) {
|
||||||
|
DatasetTableFieldDTO dto = datasetTableFieldManage.selectById(datasetTableFieldDTO.getId());
|
||||||
|
if (ObjectUtils.isEmpty(dto)) {
|
||||||
|
if (Objects.equals(datasetTableFieldDTO.getExtField(), ExtFieldConstant.EXT_NORMAL)) {
|
||||||
|
for (DatasetTableFieldDTO fieldDTO : unionFields) {
|
||||||
|
if (Objects.equals(datasetTableFieldDTO.getDatasetTableId(), fieldDTO.getDatasetTableId())
|
||||||
|
&& Objects.equals(datasetTableFieldDTO.getOriginName(), fieldDTO.getOriginName())) {
|
||||||
|
datasetTableFieldDTO.setDataeaseName(fieldDTO.getDataeaseName());
|
||||||
|
datasetTableFieldDTO.setFieldShortName(fieldDTO.getFieldShortName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Objects.equals(datasetTableFieldDTO.getExtField(), ExtFieldConstant.EXT_CALC)) {
|
||||||
|
String dataeaseName = TableUtils.fieldNameShort(datasetTableFieldDTO.getId() + "_" + datasetTableFieldDTO.getOriginName());
|
||||||
|
datasetTableFieldDTO.setDataeaseName(dataeaseName);
|
||||||
|
datasetTableFieldDTO.setFieldShortName(dataeaseName);
|
||||||
|
datasetTableFieldDTO.setDeExtractType(datasetTableFieldDTO.getDeType());
|
||||||
|
}
|
||||||
|
if (Objects.equals(datasetTableFieldDTO.getExtField(), ExtFieldConstant.EXT_GROUP)) {
|
||||||
|
String dataeaseName = TableUtils.fieldNameShort(datasetTableFieldDTO.getId() + "_" + datasetTableFieldDTO.getOriginName());
|
||||||
|
datasetTableFieldDTO.setDataeaseName(dataeaseName);
|
||||||
|
datasetTableFieldDTO.setFieldShortName(dataeaseName);
|
||||||
|
datasetTableFieldDTO.setDeExtractType(0);
|
||||||
|
datasetTableFieldDTO.setDeType(0);
|
||||||
|
datasetTableFieldDTO.setGroupType("d");
|
||||||
|
}
|
||||||
|
datasetTableFieldDTO.setDatasetGroupId(datasetGroupId);
|
||||||
|
} else {
|
||||||
|
datasetTableFieldDTO.setDataeaseName(dto.getDataeaseName());
|
||||||
|
datasetTableFieldDTO.setFieldShortName(dto.getFieldShortName());
|
||||||
|
}
|
||||||
|
datasetTableFieldDTO = datasetTableFieldManage.save(datasetTableFieldDTO);
|
||||||
|
fieldIds.add(datasetTableFieldDTO.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public DatasetGroupInfoDTO getForCount(Long id) throws Exception {
|
||||||
|
CoreDatasetGroup coreDatasetGroup = coreDatasetGroupMapper.selectById(id);
|
||||||
|
if (coreDatasetGroup == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
DatasetGroupInfoDTO dto = new DatasetGroupInfoDTO();
|
||||||
|
BeanUtils.copyBean(dto, coreDatasetGroup);
|
||||||
|
if (StringUtils.equalsIgnoreCase(dto.getNodeType(), "dataset")) {
|
||||||
|
dto.setUnion(JsonUtil.parseList(coreDatasetGroup.getInfo(), new TypeReference<>() {
|
||||||
|
}));
|
||||||
|
// 获取field
|
||||||
|
List<DatasetTableFieldDTO> dsFields = datasetTableFieldManage.selectByDatasetGroupId(id);
|
||||||
|
List<DatasetTableFieldDTO> allFields = dsFields.stream().map(ele -> {
|
||||||
|
DatasetTableFieldDTO datasetTableFieldDTO = new DatasetTableFieldDTO();
|
||||||
|
BeanUtils.copyBean(datasetTableFieldDTO, ele);
|
||||||
|
datasetTableFieldDTO.setFieldShortName(ele.getDataeaseName());
|
||||||
|
return datasetTableFieldDTO;
|
||||||
|
}).collect(Collectors.toList());
|
||||||
|
|
||||||
|
dto.setAllFields(allFields);
|
||||||
|
}
|
||||||
|
return dto;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DatasetGroupInfoDTO getDetail(Long id) throws Exception {
|
||||||
|
CoreDatasetGroup coreDatasetGroup = coreDatasetGroupMapper.selectById(id);
|
||||||
|
if (coreDatasetGroup == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
DatasetGroupInfoDTO dto = new DatasetGroupInfoDTO();
|
||||||
|
BeanUtils.copyBean(dto, coreDatasetGroup);
|
||||||
|
// get creator
|
||||||
|
String userName = coreUserManage.getUserName(Long.valueOf(dto.getCreateBy()));
|
||||||
|
if (StringUtils.isNotBlank(userName)) {
|
||||||
|
dto.setCreator(userName);
|
||||||
|
}
|
||||||
|
String updateUserName = coreUserManage.getUserName(Long.valueOf(dto.getUpdateBy()));
|
||||||
|
if (StringUtils.isNotBlank(updateUserName)) {
|
||||||
|
dto.setUpdater(updateUserName);
|
||||||
|
}
|
||||||
|
dto.setUnionSql(null);
|
||||||
|
if (StringUtils.equalsIgnoreCase(dto.getNodeType(), "dataset")) {
|
||||||
|
List<UnionDTO> unionDTOList = JsonUtil.parseList(coreDatasetGroup.getInfo(), new TypeReference<>() {
|
||||||
|
});
|
||||||
|
dto.setUnion(unionDTOList);
|
||||||
|
|
||||||
|
// 获取field
|
||||||
|
List<DatasetTableFieldDTO> dsFields = datasetTableFieldManage.selectByDatasetGroupId(id);
|
||||||
|
List<DatasetTableFieldDTO> allFields = dsFields.stream().map(ele -> {
|
||||||
|
DatasetTableFieldDTO datasetTableFieldDTO = new DatasetTableFieldDTO();
|
||||||
|
BeanUtils.copyBean(datasetTableFieldDTO, ele);
|
||||||
|
datasetTableFieldDTO.setFieldShortName(ele.getDataeaseName());
|
||||||
|
return datasetTableFieldDTO;
|
||||||
|
}).collect(Collectors.toList());
|
||||||
|
|
||||||
|
dto.setAllFields(allFields);
|
||||||
|
}
|
||||||
|
return dto;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DatasetGroupInfoDTO getDatasetGroupInfoDTO(Long id, String type) throws Exception {
|
||||||
|
CoreDatasetGroup coreDatasetGroup = coreDatasetGroupMapper.selectById(id);
|
||||||
|
if (coreDatasetGroup == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
DatasetGroupInfoDTO dto = new DatasetGroupInfoDTO();
|
||||||
|
BeanUtils.copyBean(dto, coreDatasetGroup);
|
||||||
|
// get creator
|
||||||
|
String userName = coreUserManage.getUserName(Long.valueOf(dto.getCreateBy()));
|
||||||
|
if (StringUtils.isNotBlank(userName)) {
|
||||||
|
dto.setCreator(userName);
|
||||||
|
}
|
||||||
|
String updateUserName = coreUserManage.getUserName(Long.valueOf(dto.getUpdateBy()));
|
||||||
|
if (StringUtils.isNotBlank(updateUserName)) {
|
||||||
|
dto.setUpdater(updateUserName);
|
||||||
|
}
|
||||||
|
dto.setUnionSql(null);
|
||||||
|
if (StringUtils.equalsIgnoreCase(dto.getNodeType(), "dataset")) {
|
||||||
|
List<UnionDTO> unionDTOList = JsonUtil.parseList(coreDatasetGroup.getInfo(), new TypeReference<>() {
|
||||||
|
});
|
||||||
|
dto.setUnion(unionDTOList);
|
||||||
|
|
||||||
|
// 获取field
|
||||||
|
List<DatasetTableFieldDTO> dsFields = datasetTableFieldManage.selectByDatasetGroupId(id);
|
||||||
|
List<DatasetTableFieldDTO> allFields = dsFields.stream().map(ele -> {
|
||||||
|
DatasetTableFieldDTO datasetTableFieldDTO = new DatasetTableFieldDTO();
|
||||||
|
BeanUtils.copyBean(datasetTableFieldDTO, ele);
|
||||||
|
datasetTableFieldDTO.setFieldShortName(ele.getDataeaseName());
|
||||||
|
return datasetTableFieldDTO;
|
||||||
|
}).collect(Collectors.toList());
|
||||||
|
|
||||||
|
dto.setAllFields(allFields);
|
||||||
|
|
||||||
|
if ("preview".equalsIgnoreCase(type)) {
|
||||||
|
// 请求数据
|
||||||
|
Map<String, Object> map = datasetDataManage.previewDataWithLimit(dto, 0, 100, true);
|
||||||
|
// 获取data,sql
|
||||||
|
Map<String, List> data = (Map<String, List>) map.get("data");
|
||||||
|
String sql = (String) map.get("sql");
|
||||||
|
Long total = (Long) map.get("total");
|
||||||
|
dto.setData(data);
|
||||||
|
dto.setSql(Base64.getEncoder().encodeToString(sql.getBytes()));
|
||||||
|
dto.setTotal(total);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dto;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<DatasetTableDTO> getDetail(List<Long> ids) {
|
||||||
|
if (ObjectUtils.isEmpty(ids)) {
|
||||||
|
DEException.throwException(Translator.get("i18n_table_id_can_not_empty"));
|
||||||
|
}
|
||||||
|
List<DatasetTableDTO> list = new ArrayList<>();
|
||||||
|
for (Long id : ids) {
|
||||||
|
CoreDatasetGroup coreDatasetGroup = coreDatasetGroupMapper.selectById(id);
|
||||||
|
if (coreDatasetGroup == null) {
|
||||||
|
list.add(null);
|
||||||
|
} else {
|
||||||
|
DatasetTableDTO dto = new DatasetTableDTO();
|
||||||
|
BeanUtils.copyBean(dto, coreDatasetGroup);
|
||||||
|
Map<String, List<DatasetTableFieldDTO>> listByDQ = datasetTableFieldManage.listByDQ(id);
|
||||||
|
dto.setFields(listByDQ);
|
||||||
|
list.add(dto);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<SqlVariableDetails> getSqlParams(List<Long> ids) {
|
||||||
|
List<SqlVariableDetails> list = new ArrayList<>();
|
||||||
|
if (ObjectUtils.isEmpty(ids)) {
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
TypeReference<List<SqlVariableDetails>> listTypeReference = new TypeReference<List<SqlVariableDetails>>() {
|
||||||
|
};
|
||||||
|
for (Long id : ids) {
|
||||||
|
List<CoreDatasetTable> datasetTables = datasetTableManage.selectByDatasetGroupId(id);
|
||||||
|
for (CoreDatasetTable datasetTable : datasetTables) {
|
||||||
|
if (StringUtils.isNotEmpty(datasetTable.getSqlVariableDetails())) {
|
||||||
|
List<SqlVariableDetails> defaultsSqlVariableDetails = JsonUtil.parseList(datasetTable.getSqlVariableDetails(), listTypeReference);
|
||||||
|
if (CollectionUtils.isNotEmpty(defaultsSqlVariableDetails)) {
|
||||||
|
List<String> fullName = new ArrayList<>();
|
||||||
|
geFullName(id, fullName);
|
||||||
|
Collections.reverse(fullName);
|
||||||
|
List<String> finalFullName = fullName;
|
||||||
|
defaultsSqlVariableDetails.forEach(sqlVariableDetails -> {
|
||||||
|
sqlVariableDetails.setDatasetGroupId(id);
|
||||||
|
sqlVariableDetails.setDatasetTableId(datasetTable.getId());
|
||||||
|
sqlVariableDetails.setDatasetFullName(String.join("/", finalFullName));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
list.addAll(defaultsSqlVariableDetails);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
list.forEach(sqlVariableDetail -> {
|
||||||
|
sqlVariableDetail.setId(sqlVariableDetail.getDatasetTableId() + "|DE|" + sqlVariableDetail.getVariableName());
|
||||||
|
sqlVariableDetail.setDeType(FieldUtils.transType2DeType(sqlVariableDetail.getType().get(0).contains("DATETIME") ? "DATETIME" : sqlVariableDetail.getType().get(0)));
|
||||||
|
});
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkMove(DatasetGroupInfoDTO datasetGroupInfoDTO) {
|
||||||
|
if (Objects.equals(datasetGroupInfoDTO.getId(), datasetGroupInfoDTO.getPid())) {
|
||||||
|
DEException.throwException(Translator.get("i18n_pid_not_eq_id"));
|
||||||
|
}
|
||||||
|
List<Long> ids = new ArrayList<>();
|
||||||
|
getParents(datasetGroupInfoDTO.getPid(), ids);
|
||||||
|
if (ids.contains(datasetGroupInfoDTO.getId())) {
|
||||||
|
DEException.throwException(Translator.get("i18n_pid_not_eq_id"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void getParents(Long pid, List<Long> ids) {
|
||||||
|
CoreDatasetGroup parent = coreDatasetGroupMapper.selectById(pid);// 查找父级folder
|
||||||
|
ids.add(parent.getId());
|
||||||
|
if (parent.getPid() != null && parent.getPid() != 0) {
|
||||||
|
getParents(parent.getPid(), ids);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void geFullName(Long pid, List<String> fullName) {
|
||||||
|
CoreDatasetGroup parent = coreDatasetGroupMapper.selectById(pid);// 查找父级folder
|
||||||
|
if (parent == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fullName.add(parent.getName());
|
||||||
|
if (parent.getId().equals(parent.getPid())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (parent.getPid() != null && parent.getPid() != 0) {
|
||||||
|
geFullName(parent.getPid(), fullName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<DatasetTableDTO> getDetailWithPerm(List<Long> ids) {
|
||||||
|
var result = new ArrayList<DatasetTableDTO>();
|
||||||
|
if (CollectionUtils.isNotEmpty(ids)) {
|
||||||
|
var dsList = coreDatasetGroupMapper.selectBatchIds(ids);
|
||||||
|
if (CollectionUtils.isNotEmpty(dsList)) {
|
||||||
|
dsList.forEach(ds -> {
|
||||||
|
DatasetTableDTO dto = new DatasetTableDTO();
|
||||||
|
BeanUtils.copyBean(dto, ds);
|
||||||
|
var fields = datasetTableFieldManage.listFieldsWithPermissions(ds.getId());
|
||||||
|
List<DatasetTableFieldDTO> dimensionList = fields.stream().filter(ele -> StringUtils.equalsIgnoreCase(ele.getGroupType(), "d")).toList();
|
||||||
|
List<DatasetTableFieldDTO> quotaList = fields.stream().filter(ele -> StringUtils.equalsIgnoreCase(ele.getGroupType(), "q")).toList();
|
||||||
|
Map<String, List<DatasetTableFieldDTO>> map = new LinkedHashMap<>();
|
||||||
|
map.put("dimensionList", dimensionList);
|
||||||
|
map.put("quotaList", quotaList);
|
||||||
|
dto.setFields(map);
|
||||||
|
result.add(dto);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,551 @@
|
|||||||
|
package io.dataease.dataset.manage;
|
||||||
|
|
||||||
|
import io.dataease.api.dataset.union.*;
|
||||||
|
import io.dataease.api.permissions.auth.dto.BusiPerCheckDTO;
|
||||||
|
import io.dataease.api.permissions.dataset.api.RowPermissionsApi;
|
||||||
|
import io.dataease.api.permissions.user.vo.UserFormVO;
|
||||||
|
import io.dataease.commons.utils.SqlparserUtils;
|
||||||
|
import io.dataease.constant.AuthEnum;
|
||||||
|
import io.dataease.dataset.constant.DatasetTableType;
|
||||||
|
import io.dataease.dataset.utils.DatasetTableTypeConstants;
|
||||||
|
import io.dataease.dataset.utils.SqlUtils;
|
||||||
|
import io.dataease.dataset.utils.TableUtils;
|
||||||
|
import io.dataease.datasource.dao.auto.entity.CoreDatasource;
|
||||||
|
import io.dataease.datasource.dao.auto.mapper.CoreDatasourceMapper;
|
||||||
|
import io.dataease.datasource.manage.DataSourceManage;
|
||||||
|
import io.dataease.datasource.manage.EngineManage;
|
||||||
|
import io.dataease.engine.constant.ExtFieldConstant;
|
||||||
|
import io.dataease.constant.SQLConstants;
|
||||||
|
import io.dataease.exception.DEException;
|
||||||
|
import io.dataease.extensions.datasource.api.PluginManageApi;
|
||||||
|
import io.dataease.extensions.datasource.dto.DatasetTableDTO;
|
||||||
|
import io.dataease.extensions.datasource.dto.DatasetTableFieldDTO;
|
||||||
|
import io.dataease.extensions.datasource.dto.DatasourceSchemaDTO;
|
||||||
|
import io.dataease.extensions.datasource.dto.DsTypeDTO;
|
||||||
|
import io.dataease.extensions.datasource.factory.ProviderFactory;
|
||||||
|
import io.dataease.extensions.datasource.model.SQLObj;
|
||||||
|
import io.dataease.extensions.datasource.provider.Provider;
|
||||||
|
import io.dataease.extensions.datasource.vo.DatasourceConfiguration;
|
||||||
|
import io.dataease.extensions.datasource.vo.XpackPluginsDatasourceVO;
|
||||||
|
import io.dataease.extensions.view.dto.ChartExtFilterDTO;
|
||||||
|
import io.dataease.extensions.view.dto.ChartExtRequest;
|
||||||
|
import io.dataease.extensions.view.dto.SqlVariableDetails;
|
||||||
|
import io.dataease.i18n.Translator;
|
||||||
|
import io.dataease.license.utils.LicenseUtil;
|
||||||
|
import io.dataease.system.manage.CorePermissionManage;
|
||||||
|
import io.dataease.utils.AuthUtils;
|
||||||
|
import io.dataease.utils.BeanUtils;
|
||||||
|
import io.dataease.utils.JsonUtil;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
|
import java.text.MessageFormat;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author Junjun
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class DatasetSQLManage {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private CoreDatasourceMapper coreDatasourceMapper;
|
||||||
|
@Resource
|
||||||
|
private EngineManage engineManage;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private CorePermissionManage corePermissionManage;
|
||||||
|
|
||||||
|
@Autowired(required = false)
|
||||||
|
private PluginManageApi pluginManage;
|
||||||
|
@Autowired(required = false)
|
||||||
|
private RowPermissionsApi rowPermissionsApi;
|
||||||
|
@Resource
|
||||||
|
private DataSourceManage dataSourceManage;
|
||||||
|
|
||||||
|
private RowPermissionsApi getRowPermissionsApi() {
|
||||||
|
return rowPermissionsApi;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Logger logger = LoggerFactory.getLogger(DatasetSQLManage.class);
|
||||||
|
|
||||||
|
private List<SqlVariableDetails> filterParameters(ChartExtRequest chartExtRequest, Long datasetTableId) {
|
||||||
|
List<SqlVariableDetails> parameters = new ArrayList<>();
|
||||||
|
if (chartExtRequest != null && ObjectUtils.isNotEmpty(chartExtRequest.getOuterParamsFilters())) {
|
||||||
|
for (ChartExtFilterDTO filterDTO : chartExtRequest.getOuterParamsFilters()) {
|
||||||
|
if (CollectionUtils.isEmpty(filterDTO.getValue())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
filterParametersAdaptor(parameters, filterDTO, datasetTableId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (chartExtRequest != null && ObjectUtils.isNotEmpty(chartExtRequest.getWebParamsFilters())) {
|
||||||
|
for (ChartExtFilterDTO filterDTO : chartExtRequest.getWebParamsFilters()) {
|
||||||
|
if (CollectionUtils.isEmpty(filterDTO.getValue())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
filterParametersAdaptor(parameters, filterDTO, datasetTableId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (chartExtRequest != null && ObjectUtils.isNotEmpty(chartExtRequest.getFilter())) {
|
||||||
|
for (ChartExtFilterDTO filterDTO : chartExtRequest.getFilter()) {
|
||||||
|
if (CollectionUtils.isEmpty(filterDTO.getValue())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
filterParametersAdaptor(parameters, filterDTO, datasetTableId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void filterParametersAdaptor(List<SqlVariableDetails> parameters, ChartExtFilterDTO filterDTO, Long datasetTableId) {
|
||||||
|
if (ObjectUtils.isNotEmpty(filterDTO.getParameters())) {
|
||||||
|
for (SqlVariableDetails parameter : filterDTO.getParameters()) {
|
||||||
|
if (parameter.getDatasetTableId().equals(datasetTableId)) {
|
||||||
|
parameter.setValue(filterDTO.getValue());
|
||||||
|
parameter.setOperator(filterDTO.getOperator());
|
||||||
|
parameters.add(parameter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, Object> getUnionSQLForEdit(DatasetGroupInfoDTO dataTableInfoDTO, ChartExtRequest chartExtRequest) throws Exception {
|
||||||
|
Map<Long, DatasourceSchemaDTO> dsMap = new LinkedHashMap<>();
|
||||||
|
List<UnionDTO> union = dataTableInfoDTO.getUnion();
|
||||||
|
// 所有选中的字段,即select后的查询字段
|
||||||
|
Map<String, String[]> checkedInfo = new LinkedHashMap<>();
|
||||||
|
List<UnionParamDTO> unionList = new ArrayList<>();
|
||||||
|
List<DatasetTableFieldDTO> checkedFields = new ArrayList<>();
|
||||||
|
String sql = "";
|
||||||
|
|
||||||
|
if (ObjectUtils.isEmpty(union)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Set<Long> allDs = getAllDs(union);
|
||||||
|
boolean isCross = allDs.size() > 1;
|
||||||
|
|
||||||
|
DatasetTableDTO currentDs = union.get(0).getCurrentDs();
|
||||||
|
|
||||||
|
// get datasource and schema,put map
|
||||||
|
String tableSchema = putObj2Map(dsMap, currentDs, isCross);
|
||||||
|
// get table
|
||||||
|
DatasetTableInfoDTO infoDTO = JsonUtil.parseObject(currentDs.getInfo(), DatasetTableInfoDTO.class);
|
||||||
|
|
||||||
|
SQLObj tableName = getUnionTable(currentDs, infoDTO, tableSchema, 0, filterParameters(chartExtRequest, currentDs.getId()), chartExtRequest == null, isCross, dsMap);
|
||||||
|
|
||||||
|
for (int i = 0; i < union.size(); i++) {
|
||||||
|
UnionDTO unionDTO = union.get(i);
|
||||||
|
DatasetTableDTO datasetTable = unionDTO.getCurrentDs();
|
||||||
|
DatasetTableInfoDTO tableInfo = JsonUtil.parseObject(datasetTable.getInfo(), DatasetTableInfoDTO.class);
|
||||||
|
|
||||||
|
String schema;
|
||||||
|
if (dsMap.containsKey(datasetTable.getDatasourceId())) {
|
||||||
|
schema = dsMap.get(datasetTable.getDatasourceId()).getSchemaAlias();
|
||||||
|
} else {
|
||||||
|
schema = putObj2Map(dsMap, datasetTable, isCross);
|
||||||
|
}
|
||||||
|
SQLObj table = getUnionTable(datasetTable, tableInfo, schema, i, filterParameters(chartExtRequest, currentDs.getId()), chartExtRequest == null, isCross, dsMap);
|
||||||
|
|
||||||
|
// 获取前端传过来选中的字段
|
||||||
|
List<DatasetTableFieldDTO> fields = unionDTO.getCurrentDsFields();
|
||||||
|
fields = fields.stream().filter(DatasetTableFieldDTO::getChecked).collect(Collectors.toList());
|
||||||
|
|
||||||
|
String[] array = fields.stream()
|
||||||
|
.map(f -> {
|
||||||
|
String alias;
|
||||||
|
if (StringUtils.isEmpty(f.getDataeaseName())) {
|
||||||
|
alias = TableUtils.fieldNameShort(table.getTableAlias() + "_" + f.getOriginName());
|
||||||
|
} else {
|
||||||
|
alias = f.getDataeaseName();
|
||||||
|
}
|
||||||
|
|
||||||
|
f.setFieldShortName(alias);
|
||||||
|
f.setDataeaseName(f.getFieldShortName());
|
||||||
|
f.setDatasetTableId(datasetTable.getId());
|
||||||
|
String prefix = "";
|
||||||
|
String suffix = "";
|
||||||
|
|
||||||
|
DsTypeDTO datasourceType = getDatasourceType(dsMap, datasetTable.getDatasourceId());
|
||||||
|
if (Objects.equals(f.getExtField(), ExtFieldConstant.EXT_NORMAL)) {
|
||||||
|
if (isCross) {
|
||||||
|
prefix = "`";
|
||||||
|
suffix = "`";
|
||||||
|
} else {
|
||||||
|
prefix = datasourceType.getPrefix();
|
||||||
|
suffix = datasourceType.getSuffix();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (StringUtils.equalsIgnoreCase(datasourceType.getType(), "es")) {
|
||||||
|
return table.getTableAlias() + "." + prefix + f.getOriginName() + suffix;
|
||||||
|
} else {
|
||||||
|
return table.getTableAlias() + "." + prefix + f.getOriginName() + suffix + " AS " + prefix + alias + suffix;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.toArray(String[]::new);
|
||||||
|
checkedInfo.put(table.getTableAlias(), array);
|
||||||
|
checkedFields.addAll(fields);
|
||||||
|
// 获取child的fields和union
|
||||||
|
if (!CollectionUtils.isEmpty(unionDTO.getChildrenDs())) {
|
||||||
|
getUnionForEdit(datasetTable, table, unionDTO.getChildrenDs(), checkedInfo, unionList, checkedFields, dsMap, chartExtRequest, isCross);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// build sql
|
||||||
|
boolean isFullJoin = false;
|
||||||
|
if (!CollectionUtils.isEmpty(unionList)) {
|
||||||
|
// field
|
||||||
|
StringBuilder field = new StringBuilder();
|
||||||
|
for (Map.Entry<String, String[]> next : checkedInfo.entrySet()) {
|
||||||
|
if (next.getValue().length > 0) {
|
||||||
|
field.append(StringUtils.join(next.getValue(), ",")).append(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String f = subPrefixSuffixChar(field.toString());
|
||||||
|
// join
|
||||||
|
StringBuilder join = new StringBuilder();
|
||||||
|
for (UnionParamDTO unionParamDTO : unionList) {
|
||||||
|
// get join type
|
||||||
|
String joinType = convertUnionTypeToSQL(unionParamDTO.getUnionType());
|
||||||
|
// 如果不是全连接则需要校验连接方式
|
||||||
|
if (!isFullJoin) {
|
||||||
|
if (StringUtils.equalsIgnoreCase(unionParamDTO.getUnionType(), "full")) {
|
||||||
|
isFullJoin = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SQLObj parentSQLObj = unionParamDTO.getParentSQLObj();
|
||||||
|
SQLObj currentSQLObj = unionParamDTO.getCurrentSQLObj();
|
||||||
|
DatasetTableDTO parentDs = unionParamDTO.getParentDs();
|
||||||
|
DatasetTableDTO currentDs1 = unionParamDTO.getCurrentDs();
|
||||||
|
|
||||||
|
String ts = "";
|
||||||
|
String tablePrefix = "";
|
||||||
|
String tableSuffix = "";
|
||||||
|
if (ObjectUtils.isNotEmpty(currentSQLObj.getTableSchema())) {
|
||||||
|
if (isCross) {
|
||||||
|
tablePrefix = "`";
|
||||||
|
tableSuffix = "`";
|
||||||
|
} else {
|
||||||
|
DsTypeDTO datasourceType = getDatasourceType(dsMap, currentDs1.getDatasourceId());
|
||||||
|
tablePrefix = datasourceType.getPrefix();
|
||||||
|
tableSuffix = datasourceType.getSuffix();
|
||||||
|
}
|
||||||
|
|
||||||
|
ts = tablePrefix + currentSQLObj.getTableSchema() + tableSuffix + ".";
|
||||||
|
}
|
||||||
|
// build join
|
||||||
|
join.append(" ").append(joinType).append(" ")
|
||||||
|
.append(ts)
|
||||||
|
.append(tablePrefix + currentSQLObj.getTableName() + tableSuffix)
|
||||||
|
.append(" ").append(currentSQLObj.getTableAlias()).append(" ")
|
||||||
|
.append(" ON ");
|
||||||
|
if (unionParamDTO.getUnionFields().size() == 0) {
|
||||||
|
DEException.throwException(Translator.get("i18n_union_field_can_not_empty"));
|
||||||
|
}
|
||||||
|
for (int i = 0; i < unionParamDTO.getUnionFields().size(); i++) {
|
||||||
|
UnionItemDTO unionItemDTO = unionParamDTO.getUnionFields().get(i);
|
||||||
|
// 通过field id取得field详情,并且以第一组为准,寻找dataset table
|
||||||
|
DatasetTableFieldDTO parentField = unionItemDTO.getParentField();
|
||||||
|
DatasetTableFieldDTO currentField = unionItemDTO.getCurrentField();
|
||||||
|
String pPrefix = "";
|
||||||
|
String pSuffix = "";
|
||||||
|
if (Objects.equals(parentField.getExtField(), ExtFieldConstant.EXT_NORMAL)) {
|
||||||
|
if (isCross) {
|
||||||
|
pPrefix = "`";
|
||||||
|
pSuffix = "`";
|
||||||
|
} else {
|
||||||
|
DsTypeDTO datasourceType = getDatasourceType(dsMap, parentDs.getDatasourceId());
|
||||||
|
pPrefix = datasourceType.getPrefix();
|
||||||
|
pSuffix = datasourceType.getSuffix();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String cPrefix = "";
|
||||||
|
String cSuffix = "";
|
||||||
|
if (Objects.equals(currentField.getExtField(), ExtFieldConstant.EXT_NORMAL)) {
|
||||||
|
if (isCross) {
|
||||||
|
cPrefix = "`";
|
||||||
|
cSuffix = "`";
|
||||||
|
} else {
|
||||||
|
DsTypeDTO datasourceType = getDatasourceType(dsMap, currentDs1.getDatasourceId());
|
||||||
|
cPrefix = datasourceType.getPrefix();
|
||||||
|
cSuffix = datasourceType.getSuffix();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
join.append(parentSQLObj.getTableAlias()).append(".")
|
||||||
|
.append(pPrefix + parentField.getOriginName() + pSuffix)
|
||||||
|
.append(" = ")
|
||||||
|
.append(currentSQLObj.getTableAlias()).append(".")
|
||||||
|
.append(cPrefix + currentField.getOriginName() + cSuffix);
|
||||||
|
if (i < unionParamDTO.getUnionFields().size() - 1) {
|
||||||
|
join.append(" AND ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (StringUtils.isEmpty(f)) {
|
||||||
|
DEException.throwException(Translator.get("i18n_union_ds_no_checked"));
|
||||||
|
}
|
||||||
|
sql = MessageFormat.format("SELECT {0} FROM {1}", f, TableUtils.getTableAndAlias(tableName, getDatasourceType(dsMap, currentDs.getDatasourceId()), isCross)) + join.toString();
|
||||||
|
} else {
|
||||||
|
String f = StringUtils.join(checkedInfo.get(tableName.getTableAlias()), ",");
|
||||||
|
if (StringUtils.isEmpty(f)) {
|
||||||
|
DEException.throwException(Translator.get("i18n_union_ds_no_checked"));
|
||||||
|
}
|
||||||
|
sql = MessageFormat.format("SELECT {0} FROM {1}", f, TableUtils.getTableAndAlias(tableName, getDatasourceType(dsMap, currentDs.getDatasourceId()), isCross));
|
||||||
|
}
|
||||||
|
logger.debug("calcite origin sql: " + sql);
|
||||||
|
Map<String, Object> map = new HashMap<>();
|
||||||
|
map.put("sql", sql);
|
||||||
|
map.put("field", checkedFields);
|
||||||
|
map.put("join", unionList);
|
||||||
|
map.put("dsMap", dsMap);
|
||||||
|
map.put("isFullJoin", isFullJoin);
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 递归计算出所有子级的checkedFields和unionParam
|
||||||
|
private void getUnionForEdit(DatasetTableDTO parentTable, SQLObj parentSQLObj,
|
||||||
|
List<UnionDTO> childrenDs, Map<String, String[]> checkedInfo,
|
||||||
|
List<UnionParamDTO> unionList, List<DatasetTableFieldDTO> checkedFields,
|
||||||
|
Map<Long, DatasourceSchemaDTO> dsMap, ChartExtRequest chartExtRequest,
|
||||||
|
boolean isCross) throws Exception {
|
||||||
|
for (int i = 0; i < childrenDs.size(); i++) {
|
||||||
|
int index = unionList.size() + 1;
|
||||||
|
|
||||||
|
UnionDTO unionDTO = childrenDs.get(i);
|
||||||
|
DatasetTableDTO datasetTable = unionDTO.getCurrentDs();
|
||||||
|
DatasetTableInfoDTO tableInfo = JsonUtil.parseObject(datasetTable.getInfo(), DatasetTableInfoDTO.class);
|
||||||
|
|
||||||
|
String schema;
|
||||||
|
if (dsMap.containsKey(datasetTable.getDatasourceId())) {
|
||||||
|
schema = dsMap.get(datasetTable.getDatasourceId()).getSchemaAlias();
|
||||||
|
} else {
|
||||||
|
schema = putObj2Map(dsMap, datasetTable, isCross);
|
||||||
|
}
|
||||||
|
SQLObj table = getUnionTable(datasetTable, tableInfo, schema, index, filterParameters(chartExtRequest, datasetTable.getId()), chartExtRequest == null, isCross, dsMap);
|
||||||
|
|
||||||
|
List<DatasetTableFieldDTO> fields = unionDTO.getCurrentDsFields();
|
||||||
|
fields = fields.stream().filter(DatasetTableFieldDTO::getChecked).collect(Collectors.toList());
|
||||||
|
|
||||||
|
String[] array = fields.stream()
|
||||||
|
.map(f -> {
|
||||||
|
String alias;
|
||||||
|
if (StringUtils.isEmpty(f.getDataeaseName())) {
|
||||||
|
alias = TableUtils.fieldNameShort(table.getTableAlias() + "_" + f.getOriginName());
|
||||||
|
} else {
|
||||||
|
alias = f.getDataeaseName();
|
||||||
|
}
|
||||||
|
|
||||||
|
f.setFieldShortName(alias);
|
||||||
|
f.setDataeaseName(f.getFieldShortName());
|
||||||
|
f.setDatasetTableId(datasetTable.getId());
|
||||||
|
String prefix = "";
|
||||||
|
String suffix = "";
|
||||||
|
if (Objects.equals(f.getExtField(), ExtFieldConstant.EXT_NORMAL)) {
|
||||||
|
if (isCross) {
|
||||||
|
prefix = "`";
|
||||||
|
suffix = "`";
|
||||||
|
} else {
|
||||||
|
DsTypeDTO datasourceType = getDatasourceType(dsMap, datasetTable.getDatasourceId());
|
||||||
|
prefix = datasourceType.getPrefix();
|
||||||
|
suffix = datasourceType.getSuffix();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return table.getTableAlias() + "." + prefix + f.getOriginName() + suffix + " AS " + prefix + alias + suffix;
|
||||||
|
})
|
||||||
|
.toArray(String[]::new);
|
||||||
|
checkedInfo.put(table.getTableAlias(), array);
|
||||||
|
checkedFields.addAll(fields);
|
||||||
|
|
||||||
|
UnionParamDTO unionToParent = unionDTO.getUnionToParent();
|
||||||
|
// 设置关联关系中,两个table信息
|
||||||
|
unionToParent.setParentDs(parentTable);
|
||||||
|
unionToParent.setParentSQLObj(parentSQLObj);
|
||||||
|
unionToParent.setCurrentDs(datasetTable);
|
||||||
|
unionToParent.setCurrentSQLObj(table);
|
||||||
|
unionList.add(unionToParent);
|
||||||
|
if (!CollectionUtils.isEmpty(unionDTO.getChildrenDs())) {
|
||||||
|
getUnionForEdit(datasetTable, table, unionDTO.getChildrenDs(), checkedInfo, unionList, checkedFields, dsMap, chartExtRequest, isCross);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<Long> getAllDs(List<UnionDTO> union) {
|
||||||
|
Set<Long> set = new HashSet<>();
|
||||||
|
for (UnionDTO unionDTO : union) {
|
||||||
|
Long datasourceId = unionDTO.getCurrentDs().getDatasourceId();
|
||||||
|
set.add(datasourceId);
|
||||||
|
getChildrenDs(unionDTO.getChildrenDs(), set);
|
||||||
|
}
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void getChildrenDs(List<UnionDTO> childrenDs, Set<Long> set) {
|
||||||
|
for (UnionDTO unionDTO : childrenDs) {
|
||||||
|
set.add(unionDTO.getCurrentDs().getDatasourceId());
|
||||||
|
if (!CollectionUtils.isEmpty(unionDTO.getChildrenDs())) {
|
||||||
|
getChildrenDs(unionDTO.getChildrenDs(), set);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private DsTypeDTO getDatasourceType(Map<Long, DatasourceSchemaDTO> dsMap, Long datasourceId) {
|
||||||
|
DatasourceSchemaDTO datasourceSchemaDTO = dsMap.get(datasourceId);
|
||||||
|
String type;
|
||||||
|
if (datasourceSchemaDTO == null) {
|
||||||
|
CoreDatasource coreDatasource = dataSourceManage.getCoreDatasource(datasourceId);
|
||||||
|
if (coreDatasource == null) {
|
||||||
|
DEException.throwException(Translator.get("i18n_dataset_ds_error") + ",ID:" + datasourceId);
|
||||||
|
}
|
||||||
|
type = engineManage.getDeEngine().getType();
|
||||||
|
} else {
|
||||||
|
type = datasourceSchemaDTO.getType();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Arrays.stream(DatasourceConfiguration.DatasourceType.values()).map(DatasourceConfiguration.DatasourceType::getType).toList().contains(type)) {
|
||||||
|
DatasourceConfiguration.DatasourceType datasourceType = DatasourceConfiguration.DatasourceType.valueOf(type);
|
||||||
|
DsTypeDTO dto = new DsTypeDTO();
|
||||||
|
BeanUtils.copyBean(dto, datasourceType);
|
||||||
|
return dto;
|
||||||
|
} else {
|
||||||
|
if (LicenseUtil.licenseValid()) {
|
||||||
|
List<XpackPluginsDatasourceVO> xpackPluginsDatasourceVOS = pluginManage.queryPluginDs();
|
||||||
|
List<XpackPluginsDatasourceVO> list = xpackPluginsDatasourceVOS.stream().filter(ele -> StringUtils.equals(ele.getType(), type)).toList();
|
||||||
|
if (ObjectUtils.isNotEmpty(list)) {
|
||||||
|
XpackPluginsDatasourceVO first = list.getFirst();
|
||||||
|
DsTypeDTO dto = new DsTypeDTO();
|
||||||
|
dto.setName(first.getName());
|
||||||
|
dto.setCatalog(first.getCategory());
|
||||||
|
dto.setType(first.getType());
|
||||||
|
dto.setPrefix(first.getPrefix());
|
||||||
|
dto.setSuffix(first.getSuffix());
|
||||||
|
return dto;
|
||||||
|
} else {
|
||||||
|
DEException.throwException(Translator.get("i18n_dataset_plugin_error"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String subPrefixSuffixChar(String str) {
|
||||||
|
while (StringUtils.startsWith(str, ",")) {
|
||||||
|
str = str.substring(1, str.length());
|
||||||
|
}
|
||||||
|
while (StringUtils.endsWith(str, ",")) {
|
||||||
|
str = str.substring(0, str.length() - 1);
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String convertUnionTypeToSQL(String unionType) {
|
||||||
|
switch (unionType) {
|
||||||
|
case "1:1":
|
||||||
|
case "inner":
|
||||||
|
return " INNER JOIN ";
|
||||||
|
case "1:N":
|
||||||
|
case "left":
|
||||||
|
return " LEFT JOIN ";
|
||||||
|
case "N:1":
|
||||||
|
case "right":
|
||||||
|
return " RIGHT JOIN ";
|
||||||
|
case "N:N":
|
||||||
|
case "full":
|
||||||
|
return " FULL JOIN ";
|
||||||
|
default:
|
||||||
|
return " INNER JOIN ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private UserFormVO getUserEntity() {
|
||||||
|
if (getRowPermissionsApi() == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return getRowPermissionsApi().getUserById(AuthUtils.getUser().getUserId());
|
||||||
|
}
|
||||||
|
|
||||||
|
private SQLObj getUnionTable(DatasetTableDTO currentDs, DatasetTableInfoDTO infoDTO, String tableSchema, int index, List<SqlVariableDetails> parameters, boolean isFromDataSet, boolean isCross, Map<Long, DatasourceSchemaDTO> dsMap) {
|
||||||
|
SQLObj tableObj;
|
||||||
|
String tableAlias = String.format(SQLConstants.TABLE_ALIAS_PREFIX, index);
|
||||||
|
if (StringUtils.equalsIgnoreCase(currentDs.getType(), DatasetTableTypeConstants.DATASET_TABLE_DB)) {
|
||||||
|
tableObj = SQLObj.builder().tableSchema(tableSchema).tableName(infoDTO.getTable()).tableAlias(tableAlias).build();
|
||||||
|
} else if (StringUtils.equalsIgnoreCase(currentDs.getType(), DatasetTableTypeConstants.DATASET_TABLE_SQL)) {
|
||||||
|
Provider provider = ProviderFactory.getProvider(dsMap.entrySet().iterator().next().getValue().getType());
|
||||||
|
// parser sql params and replace default value
|
||||||
|
String s = new String(Base64.getDecoder().decode(infoDTO.getSql()));
|
||||||
|
String sql = new SqlparserUtils().handleVariableDefaultValue(s, currentDs.getSqlVariableDetails(), false, isFromDataSet, parameters, isCross, dsMap, pluginManage, getUserEntity());
|
||||||
|
sql = provider.replaceComment(sql);
|
||||||
|
// add table schema
|
||||||
|
if (isCross) {
|
||||||
|
sql = SqlUtils.addSchema(sql, tableSchema);
|
||||||
|
}
|
||||||
|
tableObj = SQLObj.builder().tableSchema("").tableName("(" + sql + ")").tableAlias(tableAlias).build();
|
||||||
|
} else {
|
||||||
|
// excel,api
|
||||||
|
tableObj = SQLObj.builder().tableSchema(tableSchema).tableName(infoDTO.getTable()).tableAlias(tableAlias).build();
|
||||||
|
}
|
||||||
|
return tableObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String putObj2Map(Map<Long, DatasourceSchemaDTO> dsMap, DatasetTableDTO ds, boolean isCross) throws Exception {
|
||||||
|
// 通过datasource id校验数据源权限
|
||||||
|
BusiPerCheckDTO dto = new BusiPerCheckDTO();
|
||||||
|
dto.setId(ds.getDatasourceId());
|
||||||
|
dto.setAuthEnum(AuthEnum.READ);
|
||||||
|
boolean checked = corePermissionManage.checkAuth(dto);
|
||||||
|
if (!checked) {
|
||||||
|
DEException.throwException(Translator.get("i18n_no_datasource_permission"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
String schemaAlias;
|
||||||
|
if (StringUtils.equalsIgnoreCase(ds.getType(), DatasetTableType.DB) || StringUtils.equalsIgnoreCase(ds.getType(), DatasetTableType.SQL)) {
|
||||||
|
CoreDatasource coreDatasource = dataSourceManage.getCoreDatasource(ds.getDatasourceId());
|
||||||
|
if (coreDatasource == null) {
|
||||||
|
DEException.throwException(Translator.get("i18n_dataset_ds_error") + ",ID:" + ds.getDatasourceId());
|
||||||
|
}
|
||||||
|
if (StringUtils.equalsIgnoreCase("excel", coreDatasource.getType()) || coreDatasource.getType().contains(DatasourceConfiguration.DatasourceType.API.name())) {
|
||||||
|
coreDatasource = engineManage.getDeEngine();
|
||||||
|
}
|
||||||
|
|
||||||
|
Map map = JsonUtil.parseObject(coreDatasource.getConfiguration(), Map.class);
|
||||||
|
if (!isCross && ObjectUtils.isNotEmpty(map.get("schema"))) {
|
||||||
|
schemaAlias = (String) map.get("schema");
|
||||||
|
} else {
|
||||||
|
schemaAlias = String.format(SQLConstants.SCHEMA, coreDatasource.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dsMap.containsKey(coreDatasource.getId())) {
|
||||||
|
DatasourceSchemaDTO datasourceSchemaDTO = new DatasourceSchemaDTO();
|
||||||
|
BeanUtils.copyBean(datasourceSchemaDTO, coreDatasource);
|
||||||
|
datasourceSchemaDTO.setSchemaAlias(schemaAlias);
|
||||||
|
dsMap.put(coreDatasource.getId(), datasourceSchemaDTO);
|
||||||
|
}
|
||||||
|
} else if (StringUtils.equalsIgnoreCase(ds.getType(), DatasetTableType.Es)) {
|
||||||
|
CoreDatasource coreDatasource = dataSourceManage.getCoreDatasource(ds.getDatasourceId());
|
||||||
|
schemaAlias = String.format(SQLConstants.SCHEMA, coreDatasource.getId());
|
||||||
|
if (!dsMap.containsKey(coreDatasource.getId())) {
|
||||||
|
DatasourceSchemaDTO datasourceSchemaDTO = new DatasourceSchemaDTO();
|
||||||
|
BeanUtils.copyBean(datasourceSchemaDTO, coreDatasource);
|
||||||
|
datasourceSchemaDTO.setSchemaAlias(schemaAlias);
|
||||||
|
dsMap.put(coreDatasource.getId(), datasourceSchemaDTO);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
CoreDatasource coreDatasource = engineManage.getDeEngine();
|
||||||
|
schemaAlias = String.format(SQLConstants.SCHEMA, coreDatasource.getId());
|
||||||
|
if (!dsMap.containsKey(coreDatasource.getId())) {
|
||||||
|
DatasourceSchemaDTO datasourceSchemaDTO = new DatasourceSchemaDTO();
|
||||||
|
BeanUtils.copyBean(datasourceSchemaDTO, coreDatasource);
|
||||||
|
datasourceSchemaDTO.setSchemaAlias(schemaAlias);
|
||||||
|
dsMap.put(coreDatasource.getId(), datasourceSchemaDTO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return schemaAlias;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,332 @@
|
|||||||
|
package io.dataease.dataset.manage;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
|
import io.dataease.api.dataset.union.DatasetGroupInfoDTO;
|
||||||
|
import io.dataease.dataset.dao.auto.entity.CoreDatasetTableField;
|
||||||
|
import io.dataease.dataset.dao.auto.mapper.CoreDatasetTableFieldMapper;
|
||||||
|
import io.dataease.dataset.utils.TableUtils;
|
||||||
|
import io.dataease.engine.constant.ExtFieldConstant;
|
||||||
|
import io.dataease.engine.func.FunctionConstant;
|
||||||
|
import io.dataease.engine.utils.Utils;
|
||||||
|
import io.dataease.exception.DEException;
|
||||||
|
import io.dataease.extensions.datasource.api.PluginManageApi;
|
||||||
|
import io.dataease.extensions.datasource.dto.CalParam;
|
||||||
|
import io.dataease.extensions.datasource.dto.DatasetTableFieldDTO;
|
||||||
|
import io.dataease.extensions.datasource.dto.DatasourceSchemaDTO;
|
||||||
|
import io.dataease.extensions.datasource.dto.FieldGroupDTO;
|
||||||
|
import io.dataease.extensions.datasource.model.SQLObj;
|
||||||
|
import io.dataease.extensions.view.dto.ColumnPermissionItem;
|
||||||
|
import io.dataease.i18n.Translator;
|
||||||
|
import io.dataease.utils.AuthUtils;
|
||||||
|
import io.dataease.utils.BeanUtils;
|
||||||
|
import io.dataease.utils.IDUtils;
|
||||||
|
import io.dataease.utils.JsonUtil;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author Junjun
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@Transactional
|
||||||
|
public class DatasetTableFieldManage {
|
||||||
|
@Resource
|
||||||
|
private CoreDatasetTableFieldMapper coreDatasetTableFieldMapper;
|
||||||
|
@Resource
|
||||||
|
private PermissionManage permissionManage;
|
||||||
|
@Resource
|
||||||
|
private DatasetSQLManage datasetSQLManage;
|
||||||
|
@Resource
|
||||||
|
private DatasetGroupManage datasetGroupManage;
|
||||||
|
@Autowired(required = false)
|
||||||
|
private PluginManageApi pluginManage;
|
||||||
|
|
||||||
|
public void save(CoreDatasetTableField coreDatasetTableField) {
|
||||||
|
checkNameLength(coreDatasetTableField.getName());
|
||||||
|
if (ObjectUtils.isEmpty(coreDatasetTableField.getId())) {
|
||||||
|
coreDatasetTableField.setId(IDUtils.snowID());
|
||||||
|
coreDatasetTableFieldMapper.insert(coreDatasetTableField);
|
||||||
|
} else {
|
||||||
|
coreDatasetTableFieldMapper.updateById(coreDatasetTableField);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public DatasetTableFieldDTO chartFieldSave(DatasetTableFieldDTO datasetTableFieldDTO) {
|
||||||
|
checkNameLength(datasetTableFieldDTO.getName());
|
||||||
|
CoreDatasetTableField coreDatasetTableField = coreDatasetTableFieldMapper.selectById(datasetTableFieldDTO.getId());
|
||||||
|
QueryWrapper<CoreDatasetTableField> wrapper = new QueryWrapper<>();
|
||||||
|
wrapper.eq("name", datasetTableFieldDTO.getName());
|
||||||
|
wrapper.eq("chart_id", datasetTableFieldDTO.getChartId());
|
||||||
|
if (ObjectUtils.isNotEmpty(coreDatasetTableField)) {
|
||||||
|
wrapper.ne("id", datasetTableFieldDTO.getId());
|
||||||
|
}
|
||||||
|
List<CoreDatasetTableField> fields = coreDatasetTableFieldMapper.selectList(wrapper);
|
||||||
|
if (ObjectUtils.isNotEmpty(fields)) {
|
||||||
|
DEException.throwException(Translator.get("i18n_field_name_duplicated"));
|
||||||
|
}
|
||||||
|
datasetTableFieldDTO.setDatasetGroupId(null);
|
||||||
|
return save(datasetTableFieldDTO);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数据集保存时使用
|
||||||
|
*
|
||||||
|
* @param datasetTableFieldDTO
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public DatasetTableFieldDTO save(DatasetTableFieldDTO datasetTableFieldDTO) {
|
||||||
|
checkNameLength(datasetTableFieldDTO.getName());
|
||||||
|
CoreDatasetTableField coreDatasetTableField = coreDatasetTableFieldMapper.selectById(datasetTableFieldDTO.getId());
|
||||||
|
CoreDatasetTableField record = transDTO2Record(datasetTableFieldDTO);
|
||||||
|
if (ObjectUtils.isEmpty(record.getDataeaseName())) {
|
||||||
|
String n = TableUtils.fieldNameShort(record.getId() + "");
|
||||||
|
record.setFieldShortName(n);
|
||||||
|
record.setDataeaseName(n);
|
||||||
|
}
|
||||||
|
if (ObjectUtils.isEmpty(coreDatasetTableField)) {
|
||||||
|
coreDatasetTableFieldMapper.insert(record);
|
||||||
|
} else {
|
||||||
|
coreDatasetTableFieldMapper.updateById(record);
|
||||||
|
}
|
||||||
|
return datasetTableFieldDTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DatasetTableFieldDTO saveField(DatasetTableFieldDTO datasetTableFieldDTO) {
|
||||||
|
CoreDatasetTableField record = new CoreDatasetTableField();
|
||||||
|
if (ObjectUtils.isEmpty(datasetTableFieldDTO.getId())) {
|
||||||
|
datasetTableFieldDTO.setId(IDUtils.snowID());
|
||||||
|
BeanUtils.copyBean(record, datasetTableFieldDTO);
|
||||||
|
coreDatasetTableFieldMapper.insert(record);
|
||||||
|
} else {
|
||||||
|
BeanUtils.copyBean(record, datasetTableFieldDTO);
|
||||||
|
coreDatasetTableFieldMapper.updateById(record);
|
||||||
|
}
|
||||||
|
return datasetTableFieldDTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<DatasetTableFieldDTO> getChartCalcFields(Long chartId) {
|
||||||
|
QueryWrapper<CoreDatasetTableField> wrapper = new QueryWrapper<>();
|
||||||
|
wrapper.eq("chart_id", chartId);
|
||||||
|
return transDTO(coreDatasetTableFieldMapper.selectList(wrapper));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deleteById(Long id) {
|
||||||
|
coreDatasetTableFieldMapper.deleteById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deleteByDatasetTableUpdate(Long datasetTableId, List<Long> fieldIds) {
|
||||||
|
if (!CollectionUtils.isEmpty(fieldIds)) {
|
||||||
|
QueryWrapper<CoreDatasetTableField> wrapper = new QueryWrapper<>();
|
||||||
|
wrapper.eq("dataset_table_id", datasetTableId);
|
||||||
|
wrapper.notIn("id", fieldIds);
|
||||||
|
coreDatasetTableFieldMapper.delete(wrapper);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deleteByDatasetGroupUpdate(Long datasetGroupId, List<Long> fieldIds) {
|
||||||
|
if (!CollectionUtils.isEmpty(fieldIds)) {
|
||||||
|
QueryWrapper<CoreDatasetTableField> wrapper = new QueryWrapper<>();
|
||||||
|
wrapper.eq("dataset_group_id", datasetGroupId);
|
||||||
|
wrapper.notIn("id", fieldIds);
|
||||||
|
coreDatasetTableFieldMapper.delete(wrapper);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deleteByDatasetGroupDelete(Long datasetGroupId) {
|
||||||
|
QueryWrapper<CoreDatasetTableField> wrapper = new QueryWrapper<>();
|
||||||
|
wrapper.eq("dataset_group_id", datasetGroupId);
|
||||||
|
coreDatasetTableFieldMapper.delete(wrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deleteByChartId(Long chartId) {
|
||||||
|
QueryWrapper<CoreDatasetTableField> wrapper = new QueryWrapper<>();
|
||||||
|
wrapper.eq("chart_id", chartId);
|
||||||
|
coreDatasetTableFieldMapper.delete(wrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<DatasetTableFieldDTO> selectByDatasetTableId(Long id) {
|
||||||
|
QueryWrapper<CoreDatasetTableField> wrapper = new QueryWrapper<>();
|
||||||
|
wrapper.eq("dataset_table_id", id);
|
||||||
|
return transDTO(coreDatasetTableFieldMapper.selectList(wrapper));
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<DatasetTableFieldDTO> selectByDatasetGroupId(Long id) {
|
||||||
|
QueryWrapper<CoreDatasetTableField> wrapper = new QueryWrapper<>();
|
||||||
|
wrapper.eq("dataset_group_id", id);
|
||||||
|
wrapper.eq("checked", true);
|
||||||
|
wrapper.isNull("chart_id");
|
||||||
|
return transDTO(coreDatasetTableFieldMapper.selectList(wrapper));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, List<DatasetTableFieldDTO>> selectByDatasetGroupIds(List<Long> ids) {
|
||||||
|
Map<String, List<DatasetTableFieldDTO>> map = new HashMap<>();
|
||||||
|
for (Long id : ids) {
|
||||||
|
QueryWrapper<CoreDatasetTableField> wrapper = new QueryWrapper<>();
|
||||||
|
wrapper.eq("dataset_group_id", id);
|
||||||
|
wrapper.eq("checked", true);
|
||||||
|
wrapper.isNull("chart_id");
|
||||||
|
wrapper.eq("ext_field", 0);
|
||||||
|
map.put(String.valueOf(id), transDTO(coreDatasetTableFieldMapper.selectList(wrapper)));
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<DatasetTableFieldDTO> selectByFieldIds(List<Long> ids) {
|
||||||
|
QueryWrapper<CoreDatasetTableField> wrapper = new QueryWrapper<>();
|
||||||
|
wrapper.in("id", ids);
|
||||||
|
return transDTO(coreDatasetTableFieldMapper.selectList(wrapper));
|
||||||
|
}
|
||||||
|
|
||||||
|
public DatasetTableFieldDTO selectById(Long id) {
|
||||||
|
CoreDatasetTableField coreDatasetTableField = coreDatasetTableFieldMapper.selectById(id);
|
||||||
|
if (coreDatasetTableField == null) return null;
|
||||||
|
return transObj(coreDatasetTableField);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回维度、指标列表
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Map<String, List<DatasetTableFieldDTO>> listByDQ(Long id) {
|
||||||
|
QueryWrapper<CoreDatasetTableField> wrapper = new QueryWrapper<>();
|
||||||
|
wrapper.eq("dataset_group_id", id);
|
||||||
|
wrapper.eq("checked", true);
|
||||||
|
List<DatasetTableFieldDTO> list = transDTO(coreDatasetTableFieldMapper.selectList(wrapper));
|
||||||
|
List<DatasetTableFieldDTO> dimensionList = list.stream().filter(ele -> StringUtils.equalsIgnoreCase(ele.getGroupType(), "d")).collect(Collectors.toList());
|
||||||
|
List<DatasetTableFieldDTO> quotaList = list.stream().filter(ele -> StringUtils.equalsIgnoreCase(ele.getGroupType(), "q")).collect(Collectors.toList());
|
||||||
|
Map<String, List<DatasetTableFieldDTO>> map = new LinkedHashMap<>();
|
||||||
|
map.put("dimensionList", dimensionList);
|
||||||
|
map.put("quotaList", quotaList);
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, List<DatasetTableFieldDTO>> copilotFields(Long id) throws Exception {
|
||||||
|
DatasetGroupInfoDTO datasetGroupInfoDTO = datasetGroupManage.getDatasetGroupInfoDTO(id, null);
|
||||||
|
Map<String, Object> sqlMap = datasetSQLManage.getUnionSQLForEdit(datasetGroupInfoDTO, null);
|
||||||
|
Map<Long, DatasourceSchemaDTO> dsMap = (Map<Long, DatasourceSchemaDTO>) sqlMap.get("dsMap");
|
||||||
|
boolean crossDs = Utils.isCrossDs(dsMap);
|
||||||
|
if (crossDs) {
|
||||||
|
DEException.throwException(Translator.get("i18n_dataset_cross_error"));
|
||||||
|
}
|
||||||
|
if (!isCopilotSupport(dsMap)) {
|
||||||
|
DEException.throwException(Translator.get("i18n_copilot_ds"));
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryWrapper<CoreDatasetTableField> wrapper = new QueryWrapper<>();
|
||||||
|
wrapper.eq("dataset_group_id", id);
|
||||||
|
wrapper.eq("checked", true);
|
||||||
|
wrapper.eq("ext_field", 0);
|
||||||
|
List<DatasetTableFieldDTO> list = transDTO(coreDatasetTableFieldMapper.selectList(wrapper));
|
||||||
|
|
||||||
|
Map<String, ColumnPermissionItem> desensitizationList = new HashMap<>();
|
||||||
|
list = permissionManage.filterColumnPermissions(list, desensitizationList, id, null);
|
||||||
|
|
||||||
|
List<DatasetTableFieldDTO> dimensionList = list.stream().filter(ele -> StringUtils.equalsIgnoreCase(ele.getGroupType(), "d")).collect(Collectors.toList());
|
||||||
|
List<DatasetTableFieldDTO> quotaList = list.stream().filter(ele -> StringUtils.equalsIgnoreCase(ele.getGroupType(), "q")).collect(Collectors.toList());
|
||||||
|
Map<String, List<DatasetTableFieldDTO>> map = new LinkedHashMap<>();
|
||||||
|
map.put("dimensionList", dimensionList);
|
||||||
|
map.put("quotaList", quotaList);
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<DatasetTableFieldDTO> listFieldsWithPermissions(Long id) {
|
||||||
|
List<DatasetTableFieldDTO> fields = selectByDatasetGroupId(id);
|
||||||
|
Map<String, ColumnPermissionItem> desensitizationList = new HashMap<>();
|
||||||
|
Long userId = AuthUtils.getUser() == null ? null : AuthUtils.getUser().getUserId();
|
||||||
|
List<DatasetTableFieldDTO> tmp = permissionManage
|
||||||
|
.filterColumnPermissions(fields, desensitizationList, id, userId)
|
||||||
|
.stream()
|
||||||
|
.sorted(Comparator.comparing(DatasetTableFieldDTO::getGroupType))
|
||||||
|
.toList();
|
||||||
|
tmp.forEach(ele -> ele.setDesensitized(desensitizationList.containsKey(ele.getDataeaseName())));
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<DatasetTableFieldDTO> listFieldsWithPermissionsRemoveAgg(Long id) {
|
||||||
|
List<DatasetTableFieldDTO> fields = selectByDatasetGroupId(id);
|
||||||
|
Map<String, ColumnPermissionItem> desensitizationList = new HashMap<>();
|
||||||
|
Long userId = AuthUtils.getUser() == null ? null : AuthUtils.getUser().getUserId();
|
||||||
|
SQLObj tableObj = new SQLObj();
|
||||||
|
tableObj.setTableAlias("");
|
||||||
|
List<DatasetTableFieldDTO> tmp = permissionManage
|
||||||
|
.filterColumnPermissions(fields, desensitizationList, id, userId)
|
||||||
|
.stream()
|
||||||
|
.filter(ele -> {
|
||||||
|
boolean flag = true;
|
||||||
|
if (Objects.equals(ele.getExtField(), ExtFieldConstant.EXT_CALC)) {
|
||||||
|
String originField = Utils.calcFieldRegex(ele, tableObj, fields, true, null, Utils.mergeParam(Utils.getParams(fields), null), pluginManage);
|
||||||
|
for (String func : FunctionConstant.AGG_FUNC) {
|
||||||
|
if (Utils.matchFunction(func, originField)) {
|
||||||
|
flag = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return flag;
|
||||||
|
})
|
||||||
|
.sorted(Comparator.comparing(DatasetTableFieldDTO::getGroupType))
|
||||||
|
.toList();
|
||||||
|
tmp.forEach(ele -> ele.setDesensitized(desensitizationList.containsKey(ele.getDataeaseName())));
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DatasetTableFieldDTO transObj(CoreDatasetTableField ele) {
|
||||||
|
DatasetTableFieldDTO dto = new DatasetTableFieldDTO();
|
||||||
|
if (ele == null) return null;
|
||||||
|
BeanUtils.copyBean(dto, ele);
|
||||||
|
if (StringUtils.isNotEmpty(ele.getParams())) {
|
||||||
|
TypeReference<List<CalParam>> tokenType = new TypeReference<>() {
|
||||||
|
};
|
||||||
|
List<CalParam> calParams = JsonUtil.parseList(ele.getParams(), tokenType);
|
||||||
|
dto.setParams(calParams);
|
||||||
|
}
|
||||||
|
if (StringUtils.isNotEmpty(ele.getGroupList())) {
|
||||||
|
TypeReference<List<FieldGroupDTO>> groupTokenType = new TypeReference<>() {
|
||||||
|
};
|
||||||
|
List<FieldGroupDTO> fieldGroups = JsonUtil.parseList(ele.getGroupList(), groupTokenType);
|
||||||
|
dto.setGroupList(fieldGroups);
|
||||||
|
}
|
||||||
|
return dto;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<DatasetTableFieldDTO> transDTO(List<CoreDatasetTableField> list) {
|
||||||
|
if (!CollectionUtils.isEmpty(list)) {
|
||||||
|
return list.stream().map(this::transObj).collect(Collectors.toList());
|
||||||
|
} else {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private CoreDatasetTableField transDTO2Record(DatasetTableFieldDTO dto) {
|
||||||
|
CoreDatasetTableField record = new CoreDatasetTableField();
|
||||||
|
BeanUtils.copyBean(record, dto);
|
||||||
|
if (ObjectUtils.isNotEmpty(dto.getParams())) {
|
||||||
|
record.setParams(JsonUtil.toJSONString(dto.getParams()).toString());
|
||||||
|
}
|
||||||
|
if (ObjectUtils.isNotEmpty(dto.getGroupList())) {
|
||||||
|
record.setGroupList(JsonUtil.toJSONString(dto.getGroupList()).toString());
|
||||||
|
}
|
||||||
|
return record;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkNameLength(String name) {
|
||||||
|
if (name != null && name.length() > 100) {
|
||||||
|
DEException.throwException(Translator.get("i18n_name_limit_100"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCopilotSupport(Map<Long, DatasourceSchemaDTO> dsMap) {
|
||||||
|
DatasourceSchemaDTO value = dsMap.entrySet().iterator().next().getValue();
|
||||||
|
return StringUtils.equalsIgnoreCase(value.getType(), "mysql");
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user