feat(图表): 图表过滤器支持复杂的与或条件设置

This commit is contained in:
junjun 2024-05-15 14:56:58 +08:00
parent 39ffbf638c
commit 2bd5c795af
13 changed files with 575 additions and 147 deletions

View File

@ -1,6 +1,7 @@
package io.dataease.chart.manage; package io.dataease.chart.manage;
import io.dataease.api.chart.dto.*; import io.dataease.api.chart.dto.*;
import io.dataease.api.chart.filter.FilterTreeObj;
import io.dataease.api.chart.request.ChartDrillRequest; import io.dataease.api.chart.request.ChartDrillRequest;
import io.dataease.api.chart.request.ChartExtRequest; import io.dataease.api.chart.request.ChartExtRequest;
import io.dataease.api.dataset.dto.SqlVariableDetails; import io.dataease.api.dataset.dto.SqlVariableDetails;
@ -65,6 +66,8 @@ public class ChartDataManage {
private ChartViewManege chartViewManege; private ChartViewManege chartViewManege;
@Resource @Resource
private PermissionManage permissionManage; private PermissionManage permissionManage;
@Resource
private ChartFilterTreeService chartFilterTreeService;
@Resource @Resource
private CorePermissionManage corePermissionManage; private CorePermissionManage corePermissionManage;
@ -165,7 +168,7 @@ public class ChartDataManage {
List<ChartViewFieldDTO> extTooltip = new ArrayList<>(view.getExtTooltip()); List<ChartViewFieldDTO> extTooltip = new ArrayList<>(view.getExtTooltip());
yAxis.addAll(extTooltip); yAxis.addAll(extTooltip);
} }
List<ChartFieldCustomFilterDTO> fieldCustomFilter = new ArrayList<>(view.getCustomFilter()); FilterTreeObj fieldCustomFilter = view.getCustomFilter();
List<ChartViewFieldDTO> drill = new ArrayList<>(view.getDrillFields()); List<ChartViewFieldDTO> drill = new ArrayList<>(view.getDrillFields());
DatasetGroupInfoDTO table = datasetGroupManage.get(view.getTableId(), null); DatasetGroupInfoDTO table = datasetGroupManage.get(view.getTableId(), null);
@ -187,16 +190,14 @@ public class ChartDataManage {
//将没有权限的列删掉 //将没有权限的列删掉
List<String> dataeaseNames = columnPermissionFields.stream().map(DatasetTableFieldDTO::getDataeaseName).collect(Collectors.toList()); List<String> dataeaseNames = columnPermissionFields.stream().map(DatasetTableFieldDTO::getDataeaseName).collect(Collectors.toList());
dataeaseNames.add("*"); dataeaseNames.add("*");
fieldCustomFilter = fieldCustomFilter.stream().filter(item -> !desensitizationList.keySet().contains(item.getDataeaseName()) && dataeaseNames.contains(item.getDataeaseName())).collect(Collectors.toList()); // fieldCustomFilter = fieldCustomFilter.stream().filter(item -> !desensitizationList.keySet().contains(item.getDataeaseName()) && dataeaseNames.contains(item.getDataeaseName())).collect(Collectors.toList());
extStack = extStack.stream().filter(item -> !desensitizationList.keySet().contains(item.getDataeaseName()) && dataeaseNames.contains(item.getDataeaseName())).collect(Collectors.toList()); extStack = extStack.stream().filter(item -> !desensitizationList.keySet().contains(item.getDataeaseName()) && dataeaseNames.contains(item.getDataeaseName())).collect(Collectors.toList());
extBubble = extBubble.stream().filter(item -> !desensitizationList.keySet().contains(item.getDataeaseName()) && dataeaseNames.contains(item.getDataeaseName())).collect(Collectors.toList()); extBubble = extBubble.stream().filter(item -> !desensitizationList.keySet().contains(item.getDataeaseName()) && dataeaseNames.contains(item.getDataeaseName())).collect(Collectors.toList());
drill = drill.stream().filter(item -> !desensitizationList.keySet().contains(item.getDataeaseName()) && dataeaseNames.contains(item.getDataeaseName())).collect(Collectors.toList()); drill = drill.stream().filter(item -> !desensitizationList.keySet().contains(item.getDataeaseName()) && dataeaseNames.contains(item.getDataeaseName())).collect(Collectors.toList());
// row permission // row permission
List<DataSetRowPermissionsTreeDTO> rowPermissionsTree = permissionManage.getRowPermissionsTree(table.getId(), chartExtRequest.getUser()); List<DataSetRowPermissionsTreeDTO> rowPermissionsTree = permissionManage.getRowPermissionsTree(table.getId(), chartExtRequest.getUser());
for (ChartFieldCustomFilterDTO ele : fieldCustomFilter) { chartFilterTreeService.searchFieldAndSet(fieldCustomFilter);
ele.setField(datasetTableFieldManage.selectById(ele.getId()));
}
if (ObjectUtils.isEmpty(xAxis) && ObjectUtils.isEmpty(yAxis)) { if (ObjectUtils.isEmpty(xAxis) && ObjectUtils.isEmpty(yAxis)) {
return emptyChartViewDTO(view); return emptyChartViewDTO(view);
@ -483,16 +484,7 @@ public class ChartDataManage {
} }
// 处理过滤条件中的单引号 // 处理过滤条件中的单引号
fieldCustomFilter = fieldCustomFilter.stream().peek(ele -> { fieldCustomFilter = chartFilterTreeService.charReplace(fieldCustomFilter);
if (ObjectUtils.isNotEmpty(ele.getEnumCheckField())) {
List<String> collect = ele.getEnumCheckField().stream().map(SQLUtils::transKeyword).collect(Collectors.toList());
ele.setEnumCheckField(collect);
}
if (ObjectUtils.isNotEmpty(ele.getFilter())) {
List<ChartCustomFilterItemDTO> collect = ele.getFilter().stream().peek(f -> f.setValue(SQLUtils.transKeyword(f.getValue()))).collect(Collectors.toList());
ele.setFilter(collect);
}
}).collect(Collectors.toList());
extFilterList = extFilterList.stream().peek(ele -> { extFilterList = extFilterList.stream().peek(ele -> {
if (ObjectUtils.isNotEmpty(ele.getValue())) { if (ObjectUtils.isNotEmpty(ele.getValue())) {
@ -1269,17 +1261,15 @@ public class ChartDataManage {
} }
List<ChartViewFieldDTO> extStack = new ArrayList<>(view.getExtStack()); List<ChartViewFieldDTO> extStack = new ArrayList<>(view.getExtStack());
List<ChartViewFieldDTO> extBubble = new ArrayList<>(view.getExtBubble()); List<ChartViewFieldDTO> extBubble = new ArrayList<>(view.getExtBubble());
List<ChartFieldCustomFilterDTO> fieldCustomFilter = new ArrayList<>(view.getCustomFilter()); FilterTreeObj fieldCustomFilter = view.getCustomFilter();
List<ChartViewFieldDTO> drill = new ArrayList<>(view.getDrillFields()); List<ChartViewFieldDTO> drill = new ArrayList<>(view.getDrillFields());
// 获取数据集,需校验权限 // 获取数据集,需校验权限
DatasetGroupInfoDTO table = datasetGroupManage.get(view.getTableId(), null);// todo DatasetGroupInfoDTO table = datasetGroupManage.get(view.getTableId(), null);
Map<String, ColumnPermissionItem> desensitizationList = new HashMap<>();// todo Map<String, ColumnPermissionItem> desensitizationList = new HashMap<>();
List<DataSetRowPermissionsTreeDTO> rowPermissionsTree = permissionManage.getRowPermissionsTree(table.getId(), view.getChartExtRequest().getUser()); List<DataSetRowPermissionsTreeDTO> rowPermissionsTree = permissionManage.getRowPermissionsTree(table.getId(), view.getChartExtRequest().getUser());
for (ChartFieldCustomFilterDTO ele : fieldCustomFilter) { chartFilterTreeService.searchFieldAndSet(fieldCustomFilter);
ele.setField(datasetTableFieldManage.selectById(ele.getId()));
}
if (ObjectUtils.isEmpty(xAxis) && ObjectUtils.isEmpty(yAxis)) { if (ObjectUtils.isEmpty(xAxis) && ObjectUtils.isEmpty(yAxis)) {
return new ArrayList<String[]>(); return new ArrayList<String[]>();

View File

@ -0,0 +1,66 @@
package io.dataease.chart.manage;
import io.dataease.api.chart.filter.FilterTreeItem;
import io.dataease.api.chart.filter.FilterTreeObj;
import io.dataease.dataset.dao.auto.entity.CoreDatasetTableField;
import io.dataease.dataset.dao.auto.mapper.CoreDatasetTableFieldMapper;
import io.dataease.dto.dataset.DatasetTableFieldDTO;
import io.dataease.engine.utils.SQLUtils;
import io.dataease.utils.BeanUtils;
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);
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;
}
}

View File

@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import io.dataease.api.chart.dto.*; import io.dataease.api.chart.dto.*;
import io.dataease.api.chart.filter.FilterTreeObj;
import io.dataease.api.dataset.union.model.SQLObj; import io.dataease.api.dataset.union.model.SQLObj;
import io.dataease.chart.dao.auto.entity.CoreChartView; import io.dataease.chart.dao.auto.entity.CoreChartView;
import io.dataease.chart.dao.auto.mapper.CoreChartViewMapper; import io.dataease.chart.dao.auto.mapper.CoreChartViewMapper;
@ -238,8 +239,6 @@ public class ChartViewManege {
TypeReference<List<ChartViewFieldDTO>> tokenType = new TypeReference<>() { TypeReference<List<ChartViewFieldDTO>> tokenType = new TypeReference<>() {
}; };
TypeReference<List<ChartFieldCustomFilterDTO>> filterTokenType = new TypeReference<>() {
};
dto.setXAxis(JsonUtil.parseList(record.getxAxis(), tokenType)); dto.setXAxis(JsonUtil.parseList(record.getxAxis(), tokenType));
dto.setXAxisExt(JsonUtil.parseList(record.getxAxisExt(), tokenType)); dto.setXAxisExt(JsonUtil.parseList(record.getxAxisExt(), tokenType));
@ -253,7 +252,7 @@ public class ChartViewManege {
dto.setCustomStyle(JsonUtil.parse(record.getCustomStyle(), Map.class)); dto.setCustomStyle(JsonUtil.parse(record.getCustomStyle(), Map.class));
dto.setSenior(JsonUtil.parse(record.getSenior(), Map.class)); dto.setSenior(JsonUtil.parse(record.getSenior(), Map.class));
dto.setDrillFields(JsonUtil.parseList(record.getDrillFields(), tokenType)); dto.setDrillFields(JsonUtil.parseList(record.getDrillFields(), tokenType));
dto.setCustomFilter(JsonUtil.parseList(record.getCustomFilter(), filterTokenType)); dto.setCustomFilter(JsonUtil.parse(record.getCustomFilter(), FilterTreeObj.class));
dto.setViewFields(JsonUtil.parseList(record.getViewFields(), tokenType)); dto.setViewFields(JsonUtil.parseList(record.getViewFields(), tokenType));
return dto; return dto;

View File

@ -0,0 +1,150 @@
package io.dataease.chart.manage;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.core.type.TypeReference;
import io.dataease.api.chart.dto.ChartCustomFilterItemDTO;
import io.dataease.api.chart.dto.ChartFieldCustomFilterDTO;
import io.dataease.api.chart.filter.FilterTreeItem;
import io.dataease.api.chart.filter.FilterTreeObj;
import io.dataease.chart.dao.auto.entity.CoreChartView;
import io.dataease.chart.dao.auto.mapper.CoreChartViewMapper;
import io.dataease.utils.JsonUtil;
import jakarta.annotation.Resource;
import org.apache.commons.collections4.CollectionUtils;
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;
}
}

View File

@ -1,7 +1,7 @@
package io.dataease.engine.trans; package io.dataease.engine.trans;
import io.dataease.api.chart.dto.ChartCustomFilterItemDTO; import io.dataease.api.chart.filter.FilterTreeItem;
import io.dataease.api.chart.dto.ChartFieldCustomFilterDTO; import io.dataease.api.chart.filter.FilterTreeObj;
import io.dataease.api.dataset.union.model.SQLMeta; import io.dataease.api.dataset.union.model.SQLMeta;
import io.dataease.api.dataset.union.model.SQLObj; import io.dataease.api.dataset.union.model.SQLObj;
import io.dataease.dataset.dto.DatasourceSchemaDTO; import io.dataease.dataset.dto.DatasourceSchemaDTO;
@ -9,6 +9,7 @@ import io.dataease.dto.dataset.DatasetTableFieldDTO;
import io.dataease.engine.constant.SQLConstants; import io.dataease.engine.constant.SQLConstants;
import io.dataease.engine.constant.SqlPlaceholderConstants; import io.dataease.engine.constant.SqlPlaceholderConstants;
import io.dataease.engine.utils.Utils; import io.dataease.engine.utils.Utils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@ -22,132 +23,159 @@ import java.util.Map;
*/ */
public class CustomWhere2Str { public class CustomWhere2Str {
public static void customWhere2sqlObj(SQLMeta meta, List<ChartFieldCustomFilterDTO> fields, List<DatasetTableFieldDTO> originFields, boolean isCross, Map<Long, DatasourceSchemaDTO> dsMap) { public static void customWhere2sqlObj(SQLMeta meta, FilterTreeObj tree, List<DatasetTableFieldDTO> originFields, boolean isCross, Map<Long, DatasourceSchemaDTO> dsMap) {
SQLObj tableObj = meta.getTable(); SQLObj tableObj = meta.getTable();
if (ObjectUtils.isEmpty(tableObj)) { if (ObjectUtils.isEmpty(tableObj)) {
return; return;
} }
List<String> res = new ArrayList<>(); List<String> res = new ArrayList<>();
Map<String, String> fieldsDialect = new HashMap<>(); // permission trees
if (ObjectUtils.isNotEmpty(fields)) { // 解析每个tree然后多个tree之间用and拼接
for (ChartFieldCustomFilterDTO request : fields) { // 每个tree如果是sub tree节点则使用递归合并成一组条件
List<SQLObj> list = new ArrayList<>(); if (ObjectUtils.isEmpty(tree)) {
DatasetTableFieldDTO field = request.getField(); return;
if (ObjectUtils.isEmpty(field)) {
continue;
}
String whereName = "";
String originName;
if (ObjectUtils.isNotEmpty(field.getExtField()) && field.getExtField() == 2) {
// 解析origin name中有关联的字段生成sql表达式
String calcFieldExp = Utils.calcFieldRegex(field.getOriginName(), tableObj, originFields, isCross, dsMap);
// 给计算字段处加一个占位符后续SQL方言转换后再替换
originName = String.format(SqlPlaceholderConstants.CALC_FIELD_PLACEHOLDER, field.getId());
fieldsDialect.put(originName, calcFieldExp);
if (isCross) {
originName = calcFieldExp;
}
} else if (ObjectUtils.isNotEmpty(field.getExtField()) && field.getExtField() == 1) {
originName = String.format(SQLConstants.FIELD_NAME, tableObj.getTableAlias(), field.getDataeaseName());
} else {
originName = String.format(SQLConstants.FIELD_NAME, tableObj.getTableAlias(), field.getDataeaseName());
}
if (field.getDeType() == 1) {
if (field.getDeExtractType() == 0 || field.getDeExtractType() == 5) {
// 此处获取标准格式的日期
whereName = String.format(SQLConstants.DE_STR_TO_DATE, originName, StringUtils.isNotEmpty(field.getDateFormat()) ? field.getDateFormat() : SQLConstants.DEFAULT_DATE_FORMAT);
}
if (field.getDeExtractType() == 2 || field.getDeExtractType() == 3 || field.getDeExtractType() == 4) {
String cast = String.format(SQLConstants.CAST, originName, SQLConstants.DEFAULT_INT_FORMAT);
// 此处获取标准格式的日期
whereName = String.format(SQLConstants.FROM_UNIXTIME, cast, SQLConstants.DEFAULT_DATE_FORMAT);
}
if (field.getDeExtractType() == 1) {
// 此处获取标准格式的日期
whereName = originName;
}
} else if (field.getDeType() == 2 || field.getDeType() == 3) {
if (field.getDeExtractType() == 0 || field.getDeExtractType() == 5) {
whereName = String.format(SQLConstants.CAST, originName, SQLConstants.DEFAULT_FLOAT_FORMAT);
}
if (field.getDeExtractType() == 1) {
whereName = String.format(SQLConstants.UNIX_TIMESTAMP, originName);
}
if (field.getDeExtractType() == 2 || field.getDeExtractType() == 4) {
whereName = originName;
}
if (field.getDeExtractType() == 3) {
whereName = String.format(SQLConstants.CAST, originName, SQLConstants.DEFAULT_FLOAT_FORMAT);
}
} else {
whereName = originName;
}
if (StringUtils.equalsIgnoreCase(request.getFilterType(), "enum")) {
if (ObjectUtils.isNotEmpty(request.getEnumCheckField())) {
res.add("(" + whereName + " IN ('" + String.join("','", request.getEnumCheckField()) + "'))");
}
} else {
if (field.getDeType() == 1) {
// 规定几种日期格式一一匹配匹配到就是该格式
whereName = String.format(SQLConstants.UNIX_TIMESTAMP, whereName);
}
List<ChartCustomFilterItemDTO> filter = request.getFilter();
for (ChartCustomFilterItemDTO filterItemDTO : filter) {
String value = filterItemDTO.getValue();
String whereTerm = Utils.transFilterTerm(filterItemDTO.getTerm());
String whereValue = "";
if (StringUtils.equalsIgnoreCase(filterItemDTO.getTerm(), "null")) {
whereValue = "";
} else if (StringUtils.equalsIgnoreCase(filterItemDTO.getTerm(), "not_null")) {
whereValue = "";
} else if (StringUtils.equalsIgnoreCase(filterItemDTO.getTerm(), "empty")) {
whereValue = "''";
} else if (StringUtils.equalsIgnoreCase(filterItemDTO.getTerm(), "not_empty")) {
whereValue = "''";
} else if (StringUtils.containsIgnoreCase(filterItemDTO.getTerm(), "in") || StringUtils.containsIgnoreCase(filterItemDTO.getTerm(), "not in")) {
whereValue = "('" + String.join("','", value.split(",")) + "')";
} else if (StringUtils.containsIgnoreCase(filterItemDTO.getTerm(), "like")) {
whereValue = "'%" + value + "%'";
} else {
// 如果是时间字段过滤当条件是等于和不等于的时候转换成between和not between
if (field.getDeType() == 1) {
if (StringUtils.equalsIgnoreCase(whereTerm, " = ")) {
whereTerm = " BETWEEN ";
// 把value类似过滤组件处理获得start time和end time
Map<String, Long> stringLongMap = Utils.parseDateTimeValue(value);
whereValue = String.format(SQLConstants.WHERE_VALUE_BETWEEN, stringLongMap.get("startTime"), stringLongMap.get("endTime"));
} else if (StringUtils.equalsIgnoreCase(whereTerm, " <> ")) {
whereTerm = " NOT BETWEEN ";
Map<String, Long> stringLongMap = Utils.parseDateTimeValue(value);
whereValue = String.format(SQLConstants.WHERE_VALUE_BETWEEN, stringLongMap.get("startTime"), stringLongMap.get("endTime"));
} else {
value = Utils.allDateFormat2Long(value) + "";
whereValue = String.format(SQLConstants.WHERE_VALUE_VALUE, value);
}
} else {
whereValue = String.format(SQLConstants.WHERE_VALUE_VALUE, value);
}
}
list.add(SQLObj.builder()
.whereField(whereName)
.whereTermAndValue(whereTerm + whereValue)
.build());
}
List<String> strList = new ArrayList<>();
list.forEach(ele -> strList.add(ele.getWhereField() + " " + ele.getWhereTermAndValue()));
if (ObjectUtils.isNotEmpty(list)) {
res.add("(" + String.join(" " + Utils.getLogic(request.getLogic()) + " ", strList) + ")");
}
}
}
meta.setCustomWheres(ObjectUtils.isNotEmpty(res) ? "(" + String.join(" AND ", res) + ")" : null);
} }
Map<String, String> fieldsDialect = new HashMap<>();
String treeExp = transTreeToWhere(tableObj, tree, fieldsDialect, originFields, isCross, dsMap);
if (StringUtils.isNotEmpty(treeExp)) {
res.add(treeExp);
}
meta.setCustomWheres(ObjectUtils.isNotEmpty(res) ? "(" + String.join(" AND ", res) + ")" : null);
meta.setCustomWheresDialect(fieldsDialect); meta.setCustomWheresDialect(fieldsDialect);
} }
private static String transTreeToWhere(SQLObj tableObj, FilterTreeObj tree, Map<String, String> fieldsDialect, List<DatasetTableFieldDTO> originFields, boolean isCross, Map<Long, DatasourceSchemaDTO> dsMap) {
if (ObjectUtils.isEmpty(tree)) {
return null;
}
String logic = tree.getLogic();
List<FilterTreeItem> items = tree.getItems();
List<String> list = new ArrayList<>();
if (CollectionUtils.isNotEmpty(items)) {
// type is item or tree
for (FilterTreeItem item : items) {
String exp = null;
if (StringUtils.equalsIgnoreCase(item.getType(), "item")) {
// 单个item拼接SQL最后根据logic汇总
exp = transTreeItem(tableObj, item, fieldsDialect, originFields, isCross, dsMap);
} else if (StringUtils.equalsIgnoreCase(item.getType(), "tree")) {
// 递归tree
exp = transTreeToWhere(tableObj, item.getSubTree(), fieldsDialect, originFields, isCross, dsMap);
}
if (StringUtils.isNotEmpty(exp)) {
list.add(exp);
}
}
}
return CollectionUtils.isNotEmpty(list) ? "(" + String.join(" " + logic + " ", list) + ")" : null;
}
private static String transTreeItem(SQLObj tableObj, FilterTreeItem item, Map<String, String> fieldsDialect, List<DatasetTableFieldDTO> originFields, boolean isCross, Map<Long, DatasourceSchemaDTO> dsMap) {
String res = null;
DatasetTableFieldDTO field = item.getField();
if (ObjectUtils.isEmpty(field)) {
return null;
}
String whereName = "";
String originName;
if (ObjectUtils.isNotEmpty(field.getExtField()) && field.getExtField() == 2) {
// 解析origin name中有关联的字段生成sql表达式
String calcFieldExp = Utils.calcFieldRegex(field.getOriginName(), tableObj, originFields, isCross, dsMap);
// 给计算字段处加一个占位符后续SQL方言转换后再替换
originName = String.format(SqlPlaceholderConstants.CALC_FIELD_PLACEHOLDER, field.getId());
fieldsDialect.put(originName, calcFieldExp);
if (isCross) {
originName = calcFieldExp;
}
} else if (ObjectUtils.isNotEmpty(field.getExtField()) && field.getExtField() == 1) {
originName = String.format(SQLConstants.FIELD_NAME, tableObj.getTableAlias(), field.getDataeaseName());
} else {
originName = String.format(SQLConstants.FIELD_NAME, tableObj.getTableAlias(), field.getDataeaseName());
}
if (field.getDeType() == 1) {
if (field.getDeExtractType() == 0 || field.getDeExtractType() == 5) {
// 此处获取标准格式的日期
whereName = String.format(SQLConstants.DE_STR_TO_DATE, originName, StringUtils.isNotEmpty(field.getDateFormat()) ? field.getDateFormat() : SQLConstants.DEFAULT_DATE_FORMAT);
}
if (field.getDeExtractType() == 2 || field.getDeExtractType() == 3 || field.getDeExtractType() == 4) {
String cast = String.format(SQLConstants.CAST, originName, SQLConstants.DEFAULT_INT_FORMAT);
// 此处获取标准格式的日期
whereName = String.format(SQLConstants.FROM_UNIXTIME, cast, SQLConstants.DEFAULT_DATE_FORMAT);
}
if (field.getDeExtractType() == 1) {
// 此处获取标准格式的日期
whereName = originName;
}
} else if (field.getDeType() == 2 || field.getDeType() == 3) {
if (field.getDeExtractType() == 0 || field.getDeExtractType() == 5) {
whereName = String.format(SQLConstants.CAST, originName, SQLConstants.DEFAULT_FLOAT_FORMAT);
}
if (field.getDeExtractType() == 1) {
whereName = String.format(SQLConstants.UNIX_TIMESTAMP, originName);
}
if (field.getDeExtractType() == 2 || field.getDeExtractType() == 4) {
whereName = originName;
}
if (field.getDeExtractType() == 3) {
whereName = String.format(SQLConstants.CAST, originName, SQLConstants.DEFAULT_FLOAT_FORMAT);
}
} else {
whereName = originName;
}
if (StringUtils.equalsIgnoreCase(item.getFilterType(), "enum")) {
if (ObjectUtils.isNotEmpty(item.getEnumValue())) {
res = "(" + whereName + " IN ('" + String.join("','", item.getEnumValue()) + "'))";
}
} else {
if (field.getDeType() == 1) {
// 规定几种日期格式一一匹配匹配到就是该格式
whereName = String.format(SQLConstants.UNIX_TIMESTAMP, whereName);
}
String value = item.getValue();
String whereTerm = Utils.transFilterTerm(item.getTerm());
String whereValue = "";
if (StringUtils.equalsIgnoreCase(item.getTerm(), "null")) {
whereValue = "";
} else if (StringUtils.equalsIgnoreCase(item.getTerm(), "not_null")) {
whereValue = "";
} else if (StringUtils.equalsIgnoreCase(item.getTerm(), "empty")) {
whereValue = "''";
} else if (StringUtils.equalsIgnoreCase(item.getTerm(), "not_empty")) {
whereValue = "''";
} else if (StringUtils.containsIgnoreCase(item.getTerm(), "in") || StringUtils.containsIgnoreCase(item.getTerm(), "not in")) {
whereValue = "('" + String.join("','", value.split(",")) + "')";
} else if (StringUtils.containsIgnoreCase(item.getTerm(), "like")) {
whereValue = "'%" + value + "%'";
} else {
// 如果是时间字段过滤当条件是等于和不等于的时候转换成between和not between
if (field.getDeType() == 1) {
if (StringUtils.equalsIgnoreCase(whereTerm, " = ")) {
whereTerm = " BETWEEN ";
// 把value类似过滤组件处理获得start time和end time
Map<String, Long> stringLongMap = Utils.parseDateTimeValue(value);
whereValue = String.format(SQLConstants.WHERE_VALUE_BETWEEN, stringLongMap.get("startTime"), stringLongMap.get("endTime"));
} else if (StringUtils.equalsIgnoreCase(whereTerm, " <> ")) {
whereTerm = " NOT BETWEEN ";
Map<String, Long> stringLongMap = Utils.parseDateTimeValue(value);
whereValue = String.format(SQLConstants.WHERE_VALUE_BETWEEN, stringLongMap.get("startTime"), stringLongMap.get("endTime"));
} else {
value = Utils.allDateFormat2Long(value) + "";
whereValue = String.format(SQLConstants.WHERE_VALUE_VALUE, value);
}
} else {
whereValue = String.format(SQLConstants.WHERE_VALUE_VALUE, value);
}
}
SQLObj build = SQLObj.builder()
.whereField(whereName)
.whereTermAndValue(whereTerm + whereValue)
.build();
res = build.getWhereField() + " " + build.getWhereTermAndValue();
}
return res;
}
} }

View File

@ -0,0 +1,45 @@
package io.dataease.listener;
import io.dataease.chart.manage.ChartViewOldDataMergeService;
import io.dataease.startup.dao.auto.entity.CoreSysStartupJob;
import io.dataease.startup.dao.auto.mapper.CoreSysStartupJobMapper;
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.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
/**
* @Author Junjun
*/
@Component
@Order(value = 4)
public class ChartFilterMergeListener implements ApplicationListener<ApplicationReadyEvent> {
private final Logger logger = LoggerFactory.getLogger(ChartFilterMergeListener.class);
public static final String JOB_ID = "chartFilterMerge";
@Resource
private CoreSysStartupJobMapper coreSysStartupJobMapper;
@Resource
private ChartViewOldDataMergeService chartViewOldDataMergeService;
@Override
public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) {
logger.info("====chart filter merge [start]====");
CoreSysStartupJob sysStartupJob = coreSysStartupJobMapper.selectById(JOB_ID);
if (ObjectUtils.isNotEmpty(sysStartupJob) && StringUtils.equalsIgnoreCase(sysStartupJob.getStatus(), "ready")) {
logger.info("====chart filter merge [doing]====");
chartViewOldDataMergeService.mergeOldData();
sysStartupJob.setStatus("done");
coreSysStartupJobMapper.updateById(sysStartupJob);
}
logger.info("====chart filter merge [end]====");
}
}

View File

@ -0,0 +1,66 @@
package io.dataease.startup.dao.auto.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
/**
* <p>
* 项目启动任务
* </p>
*
* @author fit2cloud
* @since 2024-05-15
*/
@TableName("core_sys_startup_job")
public class CoreSysStartupJob implements Serializable {
private static final long serialVersionUID = 1L;
/**
* ID
*/
private String id;
/**
* 任务名称
*/
private String name;
/**
* 任务状态
*/
private String status;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
@Override
public String toString() {
return "CoreSysStartupJob{" +
"id = " + id +
", name = " + name +
", status = " + status +
"}";
}
}

View File

@ -0,0 +1,18 @@
package io.dataease.startup.dao.auto.mapper;
import io.dataease.startup.dao.auto.entity.CoreSysStartupJob;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* <p>
* 项目启动任务 Mapper 接口
* </p>
*
* @author fit2cloud
* @since 2024-05-15
*/
@Mapper
public interface CoreSysStartupJobMapper extends BaseMapper<CoreSysStartupJob> {
}

View File

@ -1,2 +1,15 @@
alter table `core_chart_view` alter table `core_chart_view`
add aggregate bit null comment '区间条形图开启时间纬度开启聚合'; add aggregate bit null comment '区间条形图开启时间纬度开启聚合';
DROP TABLE IF EXISTS `core_sys_startup_job`;
CREATE TABLE `core_sys_startup_job`
(
`id` varchar(64) NOT NULL COMMENT 'ID',
`name` varchar(255) DEFAULT NULL COMMENT '任务名称',
`status` varchar(255) DEFAULT NULL COMMENT '任务状态',
PRIMARY KEY (`id`)
) COMMENT ='项目启动任务';
BEGIN;
INSERT INTO `core_sys_startup_job` VALUES ('chartFilterMerge', 'chartFilterMerge', 'ready');
COMMIT;

View File

@ -1,2 +1,15 @@
alter table `core_chart_view` alter table `core_chart_view`
add aggregate bit null comment '区间条形图开启时间纬度开启聚合'; add aggregate bit null comment '区间条形图开启时间纬度开启聚合';
DROP TABLE IF EXISTS `core_sys_startup_job`;
CREATE TABLE `core_sys_startup_job`
(
`id` varchar(64) NOT NULL COMMENT 'ID',
`name` varchar(255) DEFAULT NULL COMMENT '任务名称',
`status` varchar(255) DEFAULT NULL COMMENT '任务状态',
PRIMARY KEY (`id`)
) COMMENT ='项目启动任务';
BEGIN;
INSERT INTO `core_sys_startup_job` VALUES ('chartFilterMerge', 'chartFilterMerge', 'ready');
COMMIT;

View File

@ -3,6 +3,7 @@ package io.dataease.api.chart.dto;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.dataease.api.chart.filter.FilterTreeObj;
import lombok.Data; import lombok.Data;
import java.io.Serializable; import java.io.Serializable;
@ -120,7 +121,7 @@ public class ChartViewBaseDTO implements Serializable {
/** /**
* 结果过滤 * 结果过滤
*/ */
private List<ChartFieldCustomFilterDTO> customFilter; private FilterTreeObj customFilter;
/** /**
* 钻取字段 * 钻取字段

View File

@ -0,0 +1,24 @@
package io.dataease.api.chart.filter;
import io.dataease.dto.dataset.DatasetTableFieldDTO;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
/**
* @Author Junjun
*/
@Data
public class FilterTreeItem implements Serializable {
private String type;// 'item' or 'tree'
// item
private Long fieldId;
private DatasetTableFieldDTO field;// field object
private String filterType;// 'logic' or 'enum'
private String term;//'eq','not_eq','lt','le','gt','ge','in','not in','like','not like','null','not_null','empty','not_empty','between'
private String value;// 'a'
private List<String> enumValue;// ['a','b']
// tree
private FilterTreeObj subTree;
}

View File

@ -0,0 +1,15 @@
package io.dataease.api.chart.filter;
import lombok.Data;
import java.util.List;
/**
* @Author Junjun
*/
@Data
public class FilterTreeObj {
private String logic;
private List<FilterTreeItem> items;
}