merge: 合并分支

This commit is contained in:
fit2cloud-chenyw 2024-11-06 19:01:34 +08:00
commit 668dc42652
437 changed files with 162943 additions and 38711 deletions

28
.github/workflows/llm-code-review.yml vendored Normal file
View File

@ -0,0 +1,28 @@
name: LLM Code Review
permissions:
contents: read
pull-requests: write
on:
pull_request:
types: [opened, reopened, synchronize]
jobs:
llm-code-review:
runs-on: ubuntu-latest
steps:
- uses: fit2cloud/LLM-CodeReview-Action@main
env:
GITHUB_TOKEN: ${{ secrets.FIT2CLOUDRD_LLM_CODE_REVIEW_TOKEN }}
OPENAI_API_KEY: ${{ secrets.ALIYUN_LLM_API_KEY }}
LANGUAGE: Chinese
OPENAI_API_ENDPOINT: https://dashscope.aliyuncs.com/compatible-mode/v1
MODEL: qwen2-1.5b-instruct
PROMPT: "请检查下面的代码差异是否有不规范、潜在的问题或者优化建议,用中文回答。"
top_p: 1
temperature: 1
# max_tokens: 10000
MAX_PATCH_LENGTH: 10000
IGNORE_PATTERNS: "/node_modules,*.md,/dist,/.github"
FILE_PATTERNS: "*.java,*.go,*.py,*.vue,*.ts,*.js,*.css,*.scss,*.html"

View File

@ -14,18 +14,18 @@ public class MybatisPlusGenerator {
* 第一 我嫌麻烦
* 第二 后面配置会放到nacos读起来更麻烦了
*/
private static final String url = "jdbc:mysql://localhost:3306/dataease4?autoReconnect=false&useUnicode=true&characterEncoding=UTF-8&characterSetResults=UTF-8&zeroDateTimeBehavior=convertToNull&useSSL=false";
private static final String url = "jdbc:mysql://localhost:3306/dataease?autoReconnect=false&useUnicode=true&characterEncoding=UTF-8&characterSetResults=UTF-8&zeroDateTimeBehavior=convertToNull&useSSL=false";
private static final String username = "root";
private static final String password = "123456";
/**
* 业务模块例如datasource,dataset,panel等
*/
private static final String busi = "visualization";
private static final String busi = "chart";
/**
* 这是要生成代码的表名称
*/
private static final String TABLE_NAME = "visualization_link_jump_info";
private static final String TABLE_NAME = "core_chart_view";
/**
* 下面两个配置基本上不用动

View File

@ -11,16 +11,20 @@ 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;
@ -250,14 +254,159 @@ public class DefaultChartHandler extends AbstractChartPlugin {
return res;
}
protected String assistSQL(String sql, List<ChartViewFieldDTO> assistFields) {
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 (i == (assistFields.size() - 1)) {
stringBuilder.append(dto.getSummary() + "(" + dto.getOriginName() + ")");
if (crossDs) {
if (i == (assistFields.size() - 1)) {
stringBuilder.append(dto.getSummary() + "(" + dto.getOriginName() + ")");
} else {
stringBuilder.append(dto.getSummary() + "(" + dto.getOriginName() + "),");
}
} else {
stringBuilder.append(dto.getSummary() + "(" + dto.getOriginName() + "),");
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";
@ -464,7 +613,8 @@ public class DefaultChartHandler extends AbstractChartPlugin {
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) {
if (StringUtils.equalsIgnoreCase(compareCalc.getField() + "", filterDTO.getFieldId())
&& (filterDTO.getFilterType() == 0 || filterDTO.getFilterType() == 2)) {
// -1 year
try {
Calendar calendar = Calendar.getInstance();

View File

@ -120,11 +120,11 @@ public class YoyChartHandler extends DefaultChartHandler {
expandedResult.setQuerySql(originSql);
}
// 同环比数据排序
expandedResult.setOriginData(sortData(view, expandedResult.getOriginData()));
expandedResult.setOriginData(sortData(view, expandedResult.getOriginData(),formatResult));
return expandedResult;
}
public static List<String[]> sortData(ChartViewDTO view, List<String[]> data) {
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();
// 指标排序
@ -135,11 +135,9 @@ public class YoyChartHandler extends DefaultChartHandler {
ChartViewFieldDTO firstYAxis = yAxisSortList.getFirst();
boolean asc = firstYAxis.getSort().equalsIgnoreCase("asc");
// 维度指标
List<ChartViewFieldDTO> allAxisList = Stream.of(
view.getXAxis(),
view.getXAxisExt(),
view.getYAxis()
).flatMap(List::stream).toList();
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);
}

View File

@ -53,7 +53,7 @@ public class BarHandler extends YoyChartHandler {
if (CollectionUtils.isNotEmpty(assistFields)) {
var req = new DatasourceRequest();
req.setDsList(dsMap);
var assistSql = assistSQL(originSql, assistFields);
var assistSql = assistSQL(originSql, assistFields, dsMap);
req.setQuery(assistSql);
logger.debug("calcite assistSql sql: " + assistSql);
var assistData = (List<String[]>) provider.fetchResultField(req).get("data");

View File

@ -52,10 +52,10 @@ public class StackBarHandler extends BarHandler {
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);
}
groupStackDrill(noDrillFieldAxis, noDrillFilterList, fieldsToFilter, drillFields, drillRequestList);
formatResult.getAxisMap().put(ChartAxis.xAxis, noDrillFieldAxis);
result.setFilterList(noDrillFilterList);
}
return (T) result;
}

View File

@ -64,7 +64,7 @@ public class LineHandler extends YoyChartHandler {
if (CollectionUtils.isNotEmpty(assistFields)) {
var req = new DatasourceRequest();
req.setDsList(dsMap);
var assistSql = assistSQL(originSql, assistFields);
var assistSql = assistSQL(originSql, assistFields, dsMap);
req.setQuery(assistSql);
logger.debug("calcite assistSql sql: " + assistSql);
var assistData = (List<String[]>) provider.fetchResultField(req).get("data");

View File

@ -100,7 +100,7 @@ public class StackAreaHandler extends YoyChartHandler {
if (CollectionUtils.isNotEmpty(assistFields)) {
var req = new DatasourceRequest();
req.setDsList(dsMap);
var assistSql = assistSQL(originSql, assistFields);
var assistSql = assistSQL(originSql, assistFields, dsMap);
req.setQuery(assistSql);
logger.debug("calcite assist sql: " + assistSql);
var assistData = (List<String[]>) provider.fetchResultField(req).get("data");

View File

@ -47,8 +47,7 @@ public class SymbolicMapHandler extends GroupChartHandler {
var xAxis = formatResult.getAxisMap().get(ChartAxis.xAxis);
var extBubble = formatResult.getAxisMap().get(ChartAxis.extBubble);
var yAxis = formatResult.getAxisMap().get(ChartAxis.yAxis);
Map<String, Object> result = ChartDataBuild.transSymbolicMapNormalWithDetail(xAxis, yAxis, extBubble, data, detailFields, detailData);
return result;
return ChartDataBuild.transSymbolicMapNormalWithDetail(view, xAxis, yAxis, extBubble, data, detailFields, detailData);
}
@Override

View File

@ -92,7 +92,7 @@ public class MixHandler extends YoyChartHandler {
if (CollectionUtils.isNotEmpty(assistFields)) {
var req = new DatasourceRequest();
req.setDsList(dsMap);
var assistSql = assistSQL(originSql, assistFields);
var assistSql = assistSQL(originSql, assistFields, dsMap);
req.setQuery(assistSql);
logger.debug("calcite assistSql sql: " + assistSql);
var assistData = (List<String[]>) provider.fetchResultField(req).get("data");
@ -144,7 +144,7 @@ public class MixHandler extends YoyChartHandler {
if (CollectionUtils.isNotEmpty(assistFields)) {
var req = new DatasourceRequest();
req.setDsList(dsMap);
var assistSql = assistSQL(originSql, assistFields);
var assistSql = assistSQL(originSql, assistFields, dsMap);
req.setQuery(assistSql);
var assistData = (List<String[]>) provider.fetchResultField(req).get("data");
rightResult.setAssistData(assistData);

View File

@ -12,8 +12,9 @@ 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.JsonUtil;
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;
@ -21,6 +22,8 @@ import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
@Component
public class TableInfoHandler extends DefaultChartHandler {
@ -86,7 +89,7 @@ public class TableInfoHandler extends DefaultChartHandler {
pageInfo.setPageSize(chartExtRequest.getPageSize());
}
Dimension2SQLObj.dimension2sqlObj(sqlMeta, xAxis, FieldUtil.transFields(allFields), crossDs, dsMap, Utils.getParams(FieldUtil.transFields(allFields)), view.getCalParams(), pluginManage);
if(view.getIsExcelExport()){
if (view.getIsExcelExport()) {
for (int i = 0; i < xAxis.size(); i++) {
ChartViewFieldDTO fieldDTO = null;
for (ChartViewFieldDTO allField : allFields) {
@ -101,7 +104,7 @@ public class TableInfoHandler extends DefaultChartHandler {
}
}
String originSql = SQLProvider.createQuerySQL(sqlMeta, false, true, view);// 明细表强制加排序
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;
@ -135,6 +138,32 @@ public class TableInfoHandler extends DefaultChartHandler {
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;
}
}

View File

@ -1,9 +1,18 @@
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
@ -12,4 +21,29 @@ import org.springframework.stereotype.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;
}
}

View File

@ -17,6 +17,7 @@ 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;
@ -32,9 +33,28 @@ public class TablePivotHandler extends GroupChartHandler {
@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);
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;
}
@ -54,7 +74,9 @@ public class TablePivotHandler extends GroupChartHandler {
var rowAxis = view.getXAxis();
var colAxis = view.getXAxisExt();
var dataMap = new HashMap<String, Object>();
var quotaIds = view.getYAxis().stream().map(ChartViewFieldDTO::getDataeaseName).collect(Collectors.toSet());
if (CollectionUtils.isEmpty(rowAxis)) {
return dataMap;
}
// 行总计列维度聚合加上自定义字段
var row = tableTotal.getRow();
if (row.isShowGrandTotals()) {
@ -76,7 +98,7 @@ public class TablePivotHandler extends GroupChartHandler {
var tmpData = new ArrayList<Map<String, Object>>();
dataMap.put("rowSubTotal", tmpData);
for (int i = 0; i < rowAxis.size(); i++) {
if ( i == rowAxis.size() - 1) {
if (i == rowAxis.size() - 1) {
break;
}
var xAxis = new ArrayList<>(colAxis);
@ -96,7 +118,7 @@ public class TablePivotHandler extends GroupChartHandler {
}
// 列总计行维度聚合加上自定义字段
var col = tableTotal.getCol();
if (col.isShowGrandTotals()) {
if (col.isShowGrandTotals() && CollectionUtils.isNotEmpty(colAxis)) {
var yAxis = getCustomFields(view, col.getCalcTotals().getCfg());
if (!yAxis.isEmpty()) {
var result = getData(sqlMeta, rowAxis, yAxis, allFields, crossDs, dsMap, view, provider, needOrder);
@ -109,13 +131,13 @@ public class TablePivotHandler extends GroupChartHandler {
}
}
// 列小计行维度聚合自定义指标数 * (列维度的数量 - 1)
if (col.isShowSubTotals()) {
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) {
if (i == colAxis.size() - 1) {
break;
}
var xAxis = new ArrayList<>(rowAxis);
@ -153,13 +175,13 @@ public class TablePivotHandler extends GroupChartHandler {
}
}
// 行总计里面的列小计
if (row.isShowGrandTotals() && col.isShowSubTotals()) {
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) {
if (i == colAxis.size() - 1) {
break;
}
var xAxis = colAxis.subList(0, i + 1);
@ -174,13 +196,13 @@ public class TablePivotHandler extends GroupChartHandler {
}
}
// 列总计里面的行小计
if (col.isShowGrandTotals() && row.isShowGrandTotals()) {
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) {
if (i == rowAxis.size() - 1) {
break;
}
var xAxis = rowAxis.subList(0, i + 1);
@ -195,13 +217,13 @@ public class TablePivotHandler extends GroupChartHandler {
}
}
// 行小计和列小计相交部分
if (row.isShowSubTotals() && col.isShowSubTotals()) {
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) {
if (i == rowAxis.size() - 1) {
break;
}
var tmpList = new ArrayList<Map<String, Object>>();
@ -209,7 +231,7 @@ public class TablePivotHandler extends GroupChartHandler {
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) {
if (j == colAxis.size() - 1) {
break;
}
var subCol = colAxis.subList(0, j + 1);
@ -230,6 +252,14 @@ public class TablePivotHandler extends GroupChartHandler {
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;
@ -254,8 +284,8 @@ public class TablePivotHandler extends GroupChartHandler {
}
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) {
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);
@ -268,6 +298,7 @@ public class TablePivotHandler extends GroupChartHandler {
nullToBlank(data);
return Tuples.of(querySql, data);
}
private void nullToBlank(List<String[]> data) {
data.forEach(r -> {
for (int i = 0; i < r.length; i++) {
@ -285,7 +316,7 @@ public class TablePivotHandler extends GroupChartHandler {
if (!quotaIds.contains(totalCfg.getDataeaseName())) {
continue;
}
if (StringUtils.equalsIgnoreCase(totalCfg.getAggregation(), "CUSTOM")){
if (StringUtils.equalsIgnoreCase(totalCfg.getAggregation(), "CUSTOM")) {
var field = new ChartViewFieldDTO();
field.setDeType(DeTypeConstants.DE_FLOAT);
BeanUtils.copyBean(field, totalCfg);

View File

@ -9,7 +9,7 @@ import java.io.Serializable;
* </p>
*
* @author fit2cloud
* @since 2024-05-07
* @since 2024-10-23
*/
@TableName("core_chart_view")
public class CoreChartView implements Serializable {
@ -101,11 +101,21 @@ public class CoreChartView implements Serializable {
*/
private String customAttr;
/**
* 图形属性_移动端
*/
private String customAttrMobile;
/**
* 组件样式
*/
private String customStyle;
/**
* 组件样式_移动端
*/
private String customStyleMobile;
/**
* 结果过滤
*/
@ -137,7 +147,7 @@ public class CoreChartView implements Serializable {
private Long updateTime;
/**
* 缩略图
* 缩略图
*/
private String snapshot;
@ -206,8 +216,14 @@ public class CoreChartView implements Serializable {
*/
private Boolean aggregate;
/**
* 流向地图起点名称field
*/
private String flowMapStartName;
/**
* 流向地图终点名称field
*/
private String flowMapEndName;
/**
@ -215,7 +231,6 @@ public class CoreChartView implements Serializable {
*/
private String extColor;
public Long getId() {
return id;
}
@ -352,6 +367,14 @@ public class CoreChartView implements Serializable {
this.customAttr = customAttr;
}
public String getCustomAttrMobile() {
return customAttrMobile;
}
public void setCustomAttrMobile(String customAttrMobile) {
this.customAttrMobile = customAttrMobile;
}
public String getCustomStyle() {
return customStyle;
}
@ -360,6 +383,14 @@ public class CoreChartView implements Serializable {
this.customStyle = customStyle;
}
public String getCustomStyleMobile() {
return customStyleMobile;
}
public void setCustomStyleMobile(String customStyleMobile) {
this.customStyleMobile = customStyleMobile;
}
public String getCustomFilter() {
return customFilter;
}
@ -564,7 +595,9 @@ public class CoreChartView implements Serializable {
", extLabel = " + extLabel +
", extTooltip = " + extTooltip +
", customAttr = " + customAttr +
", customAttrMobile = " + customAttrMobile +
", customStyle = " + customStyle +
", customStyleMobile = " + customStyleMobile +
", customFilter = " + customFilter +
", drillFields = " + drillFields +
", senior = " + senior +
@ -585,9 +618,9 @@ public class CoreChartView implements Serializable {
", copyFrom = " + copyFrom +
", copyId = " + copyId +
", aggregate = " + aggregate +
", flowMapStartName=" + flowMapStartName +
", flowMapEndName=" + flowMapEndName +
", extColor=" + extColor +
", flowMapStartName = " + flowMapStartName +
", flowMapEndName = " + flowMapEndName +
", extColor = " + extColor +
"}";
}
}

View File

@ -10,7 +10,7 @@ import org.apache.ibatis.annotations.Mapper;
* </p>
*
* @author fit2cloud
* @since 2024-05-07
* @since 2024-10-23
*/
@Mapper
public interface CoreChartViewMapper extends BaseMapper<CoreChartView> {

View File

@ -110,7 +110,6 @@ public class ChartDataManage {
}
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"));
@ -313,11 +312,15 @@ public class ChartDataManage {
ChartViewFieldDTO nextDrillField = drill.get(i + 1);
if (!fields.contains(nextDrillField.getId())) {
nextDrillField.setSource(FieldSource.DRILL);
nextDrillField.setSort(getDrillSort(xAxis, drill.get(0)));
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);
}
}
@ -371,10 +374,7 @@ public class ChartDataManage {
provider = ProviderFactory.getProvider(dsMap.entrySet().iterator().next().getValue().getType());
}
if (ObjectUtils.isEmpty(view.getCalParams())) {
view.setCalParams(Utils.getParams(transFields(allFields)));
}
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);
@ -625,7 +625,9 @@ public class ChartDataManage {
|| 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(), "t-heatmap")
|| StringUtils.equalsIgnoreCase(view.getType(), "sankey")
) {
xAxis.addAll(xAxisExt);
}
List<ChartViewFieldDTO> yAxis = new ArrayList<>(view.getYAxis());
@ -793,4 +795,24 @@ public class ChartDataManage {
}
}
}
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());
}
}

View File

@ -335,7 +335,13 @@ public class ChartViewManege {
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()));
@ -363,7 +369,13 @@ public class ChartViewManege {
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));

View File

@ -3,6 +3,7 @@ package io.dataease.chart.manage;
import io.dataease.api.chart.request.ThresholdCheckRequest;
import io.dataease.api.chart.vo.ThresholdCheckVO;
import io.dataease.engine.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;
@ -18,6 +19,8 @@ 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;
@ -126,12 +129,13 @@ public class ChartViewThresholdManage {
String enumValueText = String.join(",", enumValue);
return fieldName + " 属于 " + "( " + enumValueText + " )";
} else {
Integer deType = map.getDeType();
String valueType = item.getValueType();
return fieldName + " " + translateTerm(item.getTerm()) + " " + formatFieldValue(item.getValue(), valueType);
return fieldName + " " + translateTerm(item.getTerm()) + " " + formatFieldValue(item.getValue(), valueType, deType);
}
}
private String formatFieldValue(String value, String valueType) {
private String formatFieldValue(String value, String valueType, Integer deType) {
if (StringUtils.isBlank(valueType)) {
valueType = "fixed";
}
@ -144,11 +148,72 @@ public class ChartViewThresholdManage {
return "最小值";
} else if (StringUtils.equals("average", value)) {
return "平均值";
} 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("");
} else if (StringUtils.equalsIgnoreCase("YYYY-MM", format)) {
unitLabels = List.of("", "");
} else if (StringUtils.equalsIgnoreCase("YYYY-MM-DD", format)) {
unitLabels = List.of("", "", "");
} else if (StringUtils.equalsIgnoreCase("HH:mm:ss", format)) {
DEException.throwException("纯时间格式不支持动态格式");
} else {
unitLabels = List.of("", "", "");
}
String unitText = unitLabels.get(unit - 1);
String suffixText = "";
if (suffix == 2) {
suffixText = "";
}
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("当年", "去年", "明年");
} else if (StringUtils.equalsIgnoreCase("YYYY-MM", format)) {
shortLabels = List.of("当月", "上个月", "下个月", "年初", "年末");
} else if (StringUtils.equalsIgnoreCase("YYYY-MM-DD", format)) {
shortLabels = List.of("今天", "昨天", "明天", "月初", "月末");
} else if (StringUtils.equalsIgnoreCase("HH:mm:ss", format)) {
shortLabels = List.of("当前", "1小时前", "1小时后");
} else {
shortLabels = List.of("今天", "昨天", "明天", "月初", "月末");
}
return shortLabels.get(timeFlag - 1);
}
} catch (Exception e) {
LogUtil.error("动态时间配置错误,请重新配置!");
return value;
}
}
private String translateTerm(String term) {
return switch (term) {
case "eq" -> "等于";
@ -250,11 +315,100 @@ public class ChartViewThresholdManage {
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();

View File

@ -5,6 +5,7 @@ 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;
@ -17,6 +18,7 @@ import io.dataease.exportCenter.manage.ExportCenterManage;
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.dto.FormatterCfgDTO;
import io.dataease.license.manage.F2CLicLimitedManage;
import io.dataease.result.ResultCode;
import io.dataease.utils.JsonUtil;
@ -38,6 +40,10 @@ 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.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@ -71,6 +77,7 @@ public class ChartDataServer implements ChartDataApi {
return Math.toIntExact(Math.min(f2CLicLimitedManage.checkDatasetLimit(), limit));
}
@DeLinkPermit("#p0.sceneId")
@Override
public ChartViewDTO getData(ChartViewDTO chartViewDTO) throws Exception {
try {
@ -111,7 +118,7 @@ public class ChartDataServer implements ChartDataApi {
Integer curLimit = getExportLimit();
if (ChartConstants.VIEW_RESULT_MODE.CUSTOM.equals(viewDTO.getResultMode())) {
Integer limitCount = viewDTO.getResultCount();
viewDTO.setResultCount(Math.min(curLimit,limitCount));
viewDTO.setResultCount(Math.min(curLimit, limitCount));
} else {
viewDTO.setResultCount(curLimit);
}
@ -121,6 +128,16 @@ public class ChartDataServer implements ChartDataApi {
request.setHeader(dsHeader);
request.setExcelTypes(dsTypes);
}
for (Object[] objects : tableRow) {
for (int i = 0; i < viewDTO.getXAxis().size(); i++) {
if (viewDTO.getXAxis().get(i).getDeType().equals(DeTypeConstants.DE_INT) || viewDTO.getXAxis().get(i).getDeType().equals(DeTypeConstants.DE_FLOAT)) {
try {
objects[i] = valueFormatter(BigDecimal.valueOf(Double.valueOf(objects[i].toString())), viewDTO.getXAxis().get(i).getFormatterCfg());
} catch (Exception ignore) {
}
}
}
}
request.setDetails(tableRow);
} catch (Exception e) {
throw new RuntimeException(e);
@ -128,6 +145,85 @@ public class ChartDataServer implements ChartDataApi {
}
public static String valueFormatter(BigDecimal value, FormatterCfgDTO formatter) {
if (value == null || formatter == 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()) {
String[] parts = value.split("\\.");
parts[0] = addThousandSeparators(parts[0]);
sb = new StringBuilder(String.join(".", parts));
}
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()) {
sb.append(suffix);
}
return sb.toString();
}
private static String addThousandSeparators(String number) {
StringBuilder sb = new StringBuilder();
int len = number.length();
int count = 0;
for (int i = len - 1; i >= 0; i--) {
sb.append(number.charAt(i));
count++;
if (count == 3 && i != 0) {
sb.append(',');
count = 0;
}
}
return sb.reverse().toString();
}
@Override
public void innerExportDetails(ChartExcelRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest httpServletRequest = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
@ -184,7 +280,7 @@ public class ChartDataServer implements ChartDataApi {
response.setContentType("application/vnd.ms-excel");
//文件名称
response.setHeader("Content-disposition", "attachment;filename=" + request.getViewName() + ".xlsx");
response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(request.getViewName(), StandardCharsets.UTF_8) + ".xlsx");
wb.write(outputStream);
outputStream.flush();
outputStream.close();
@ -301,4 +397,9 @@ public class ChartDataServer implements ChartDataApi {
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);
}
}

View File

@ -1766,7 +1766,7 @@ public class ChartDataBuild {
}
}
public static Map<String, Object> transSymbolicMapNormalWithDetail(List<ChartViewFieldDTO> xAxis, List<ChartViewFieldDTO> yAxis, List<ChartViewFieldDTO> extBubble, List<String[]> data, List<ChartViewFieldDTO> detailFields, List<String[]> detailData) {
public static Map<String, Object> transSymbolicMapNormalWithDetail(ChartViewDTO view, List<ChartViewFieldDTO> xAxis, List<ChartViewFieldDTO> yAxis, List<ChartViewFieldDTO> extBubble, List<String[]> data, List<ChartViewFieldDTO> detailFields, List<String[]> detailData) {
int detailIndex = xAxis.size();
List<ChartViewFieldDTO> realDetailFields = detailFields.subList(detailIndex, detailFields.size());
@ -1778,7 +1778,7 @@ public class ChartDataBuild {
fields.addAll(extBubble);
if (ObjectUtils.isNotEmpty(yAxis))
fields.addAll(yAxis);
Map<String, Object> map = transTableNormal(fields, null, data, new HashMap<>());
Map<String, Object> map = transTableNormal(fields, view, data, new HashMap<>());
List<Map<String, Object>> tableRow = (List<Map<String, Object>>) map.get("tableRow");
final int xEndIndex = detailIndex;
Map<String, List<String[]>> groupDataList = detailData.stream().collect(Collectors.groupingBy(item -> "(" + StringUtils.join(ArrayUtils.subarray(item, 0, xEndIndex), ")-de-(") + ")"));

View File

@ -536,7 +536,7 @@ public class SqlparserUtils {
}
}
if (filterParameter != null) {
sql = sql.replace(matcher.group(), transFilter(filterParameter));
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)) {
@ -594,15 +594,28 @@ public class SqlparserUtils {
}
private static String transFilter(SqlVariableDetails sqlVariableDetails) {
private static String transFilter(SqlVariableDetails sqlVariableDetails, Map<Long, DatasourceSchemaDTO> dsMap) {
if (sqlVariableDetails.getOperator().equals("in")) {
return "'" + String.join("','", sqlVariableDetails.getValue()) + "'";
} else if (sqlVariableDetails.getOperator().equals("between")) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(sqlVariableDetails.getType().size() > 1 ? (String) sqlVariableDetails.getType().get(1).replace("DD", "dd").replace("YYYY", "yyyy") : "yyyy");
if (StringUtils.endsWith(sqlVariableDetails.getId(), START_END_SEPARATOR)) {
return simpleDateFormat.format(new Date(Long.parseLong((String) sqlVariableDetails.getValue().get(1))));
if (StringUtils.equalsIgnoreCase(dsMap.entrySet().iterator().next().getValue().getType(), DatasourceConfiguration.DatasourceType.sqlServer.getType())
&& sqlVariableDetails.getDeType() == 0) {
return "N'" + String.join("', N'", sqlVariableDetails.getValue()) + "'";
} else {
return simpleDateFormat.format(new Date(Long.parseLong((String) sqlVariableDetails.getValue().get(0))));
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);

View File

@ -14,7 +14,7 @@ public class CommonConfig {
@Bean(destroyMethod = "shutdown")
public CommonThreadPool resourcePoolThreadPool() {
CommonThreadPool commonThreadPool = new CommonThreadPool();
commonThreadPool.setCorePoolSize(20);
commonThreadPool.setCorePoolSize(50);
commonThreadPool.setMaxQueueSize(100);
commonThreadPool.setKeepAliveSeconds(3600);
return commonThreadPool;

View File

@ -1,7 +1,10 @@
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;
@ -11,6 +14,8 @@ import static io.dataease.utils.StaticResourceUtils.ensureSuffix;
@Configuration
public class DeMvcConfig implements WebMvcConfigurer {
@Resource
private LinkInterceptor linkInterceptor;
/**
* Configuring static resource path
@ -33,4 +38,9 @@ public class DeMvcConfig implements WebMvcConfigurer {
registry.addResourceHandler(geoUrlPattern).addResourceLocations(geoDir);
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(linkInterceptor).addPathPatterns("/**");
}
}

View File

@ -104,7 +104,7 @@ public class CopilotManage {
Map<Long, DatasourceSchemaDTO> dsMap = (Map<Long, DatasourceSchemaDTO>) sqlMap.get("dsMap");
boolean crossDs = Utils.isCrossDs(dsMap);
if (crossDs) {
DEException.throwException("跨源数据集不支持该功能");
DEException.throwException(Translator.get("i18n_copilot_cross_ds_error"));
}
// 调用copilot service 获取SQL和chart struct将返回SQL中表名替换成数据集SQL
@ -302,7 +302,7 @@ public class CopilotManage {
if (StringUtils.equalsIgnoreCase(receiveDTO.getChart().getType(), "pie")) {
AxisFieldDTO column = receiveDTO.getChart().getColumn();
if (fields.size() != 2 || column == null) {
DEException.throwException("当前字段不足以构建饼图: " + JsonUtil.toJSONString(receiveDTO));
DEException.throwException("build pie error: " + JsonUtil.toJSONString(receiveDTO));
}
AxisDTO axisDTO = new AxisDTO();
AxisFieldDTO x = new AxisFieldDTO();
@ -318,7 +318,7 @@ public class CopilotManage {
y.setName(column.getName());
y.setValue(column.getValue());
} else {
DEException.throwException("当前字段不足以构建饼图: " + JsonUtil.toJSONString(receiveDTO));
DEException.throwException("build pie error: " + JsonUtil.toJSONString(receiveDTO));
}
axisDTO.setX(x);
axisDTO.setY(y);

View File

@ -6,4 +6,5 @@ package io.dataease.dataset.constant;
public class DatasetTableType {
public static String DB = "db";
public static String SQL = "sql";
public static String Es = "es";
}

View File

@ -50,6 +50,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
@ -129,6 +130,15 @@ public class DatasetDataManage {
datasourceRequest.setTable(tableInfoDTO.getTable());
}
tableFields = provider.fetchTableField(datasourceRequest);
} else if (StringUtils.equalsIgnoreCase(type, DatasetTableType.Es)) {
CoreDatasource coreDatasource = coreDatasourceMapper.selectById(datasetTableDTO.getDatasourceId());
Provider provider = ProviderFactory.getProvider(type);
DatasourceRequest datasourceRequest = new DatasourceRequest();
DatasourceSchemaDTO datasourceSchemaDTO = new DatasourceSchemaDTO();
BeanUtils.copyBean(datasourceSchemaDTO, coreDatasource);
datasourceRequest.setDatasource(datasourceSchemaDTO);
datasourceRequest.setTable(datasetTableDTO.getTableName());
tableFields = provider.fetchTableField(datasourceRequest);
} else {
// excel,api
@ -185,9 +195,7 @@ public class DatasetDataManage {
DEException.throwException(Translator.get("i18n_no_column_permission"));
}
}
buildFieldName(sqlMap, fields);
Map<Long, DatasourceSchemaDTO> dsMap = (Map<Long, DatasourceSchemaDTO>) sqlMap.get("dsMap");
DatasourceUtils.checkDsStatus(dsMap);
List<String> dsList = new ArrayList<>();
@ -202,13 +210,11 @@ public class DatasetDataManage {
}
sql = Utils.replaceSchemaAlias(sql, dsMap);
}
List<DataSetRowPermissionsTreeDTO> rowPermissionsTree = new ArrayList<>();
TokenUserBO user = AuthUtils.getUser();
if (user != null && checkPermission) {
rowPermissionsTree = permissionManage.getRowPermissionsTree(datasetGroupInfoDTO.getId(), user.getUserId());
}
Provider provider;
if (crossDs) {
provider = ProviderFactory.getDefaultProvider();
@ -236,7 +242,6 @@ public class DatasetDataManage {
DatasourceRequest datasourceRequest = new DatasourceRequest();
datasourceRequest.setQuery(querySQL);
datasourceRequest.setDsList(dsMap);
Map<String, Object> data = provider.fetchResultField(datasourceRequest);
Map<String, Object> map = new LinkedHashMap<>();
@ -448,11 +453,17 @@ public class DatasetDataManage {
LinkedHashMap<String, Object> obj = new LinkedHashMap<>();
if (row.length > 0) {
for (int j = 0; j < fields.size(); j++) {
String res = row[j];
// 如果字段类型是数值类型的小数则去除科学计数
if (fields.get(j).getDeType() == 3 && StringUtils.containsIgnoreCase(res, "E")) {
BigDecimal bigDecimal = new BigDecimal(res);
res = String.format("%.8f", bigDecimal);
}
if (desensitizationList.keySet().contains(fields.get(j).getDataeaseName())) {
obj.put(fields.get(j).getDataeaseName(), ChartDataBuild.desensitizationValue(desensitizationList.get(fields.get(j).getDataeaseName()), String.valueOf(row[j])));
obj.put(fields.get(j).getDataeaseName(), ChartDataBuild.desensitizationValue(desensitizationList.get(fields.get(j).getDataeaseName()), String.valueOf(res)));
} else {
obj.put(ObjectUtils.isNotEmpty(fields.get(j).getDataeaseName()) ?
fields.get(j).getDataeaseName() : fields.get(j).getOriginName(), row[j]);
fields.get(j).getDataeaseName() : fields.get(j).getOriginName(), res);
}
}
}
@ -561,14 +572,20 @@ public class DatasetDataManage {
provider = ProviderFactory.getProvider(dsList.getFirst());
}
String dsType = null;
if (dsMap != null && dsMap.entrySet().iterator().hasNext()) {
Map.Entry<Long, DatasourceSchemaDTO> next = dsMap.entrySet().iterator().next();
dsType = next.getValue().getType();
}
Field2SQLObj.field2sqlObj(sqlMeta, fields, allFields, crossDs, dsMap, Utils.getParams(allFields), null, pluginManage);
WhereTree2Str.transFilterTrees(sqlMeta, rowPermissionsTree, allFields, crossDs, dsMap, Utils.getParams(allFields), null, pluginManage);
Order2SQLObj.getOrders(sqlMeta, datasetGroupInfoDTO.getSortFields(), allFields, crossDs, dsMap, Utils.getParams(allFields), null, pluginManage);
String querySQL;
if (multFieldValuesRequest.getResultMode() == 0) {
querySQL = SQLProvider.createQuerySQLWithLimit(sqlMeta, false, needOrder, true, 0, 1000);
querySQL = SQLProvider.createQuerySQLWithLimit(sqlMeta, false, needOrder, !StringUtils.equalsIgnoreCase(dsType, "es"), 0, 1000);
} else {
querySQL = SQLProvider.createQuerySQL(sqlMeta, false, needOrder, true);
querySQL = SQLProvider.createQuerySQL(sqlMeta, false, needOrder, !StringUtils.equalsIgnoreCase(dsType, "es"));
}
querySQL = provider.rebuildSQL(querySQL, sqlMeta, crossDs, dsMap);
logger.debug("calcite data enum sql: " + querySQL);
@ -808,15 +825,21 @@ public class DatasetDataManage {
provider = ProviderFactory.getProvider(dsList.getFirst());
}
String dsType = null;
if (dsMap != null && dsMap.entrySet().iterator().hasNext()) {
Map.Entry<Long, DatasourceSchemaDTO> next = dsMap.entrySet().iterator().next();
dsType = next.getValue().getType();
}
Field2SQLObj.field2sqlObj(sqlMeta, fields, allFields, crossDs, dsMap, Utils.getParams(allFields), null, pluginManage);
ExtWhere2Str.extWhere2sqlOjb(sqlMeta, extFilterList, allFields, crossDs, dsMap, Utils.getParams(allFields), null, pluginManage);
WhereTree2Str.transFilterTrees(sqlMeta, rowPermissionsTree, allFields, crossDs, dsMap, Utils.getParams(allFields), null, pluginManage);
Order2SQLObj.getOrders(sqlMeta, datasetGroupInfoDTO.getSortFields(), allFields, crossDs, dsMap, Utils.getParams(allFields), null, pluginManage);
String querySQL;
if (request.getResultMode() == 0) {
querySQL = SQLProvider.createQuerySQLWithLimit(sqlMeta, false, needOrder, sortDistinct && ids.size() == 1, 0, 1000);
querySQL = SQLProvider.createQuerySQLWithLimit(sqlMeta, false, needOrder, sortDistinct && ids.size() == 1 && !StringUtils.equalsIgnoreCase(dsType, "es"), 0, 1000);
} else {
querySQL = SQLProvider.createQuerySQL(sqlMeta, false, needOrder, sortDistinct && ids.size() == 1);
querySQL = SQLProvider.createQuerySQL(sqlMeta, false, needOrder, sortDistinct && ids.size() == 1 && !StringUtils.equalsIgnoreCase(dsType, "es"));
}
querySQL = provider.rebuildSQL(querySQL, sqlMeta, crossDs, dsMap);
logger.debug("calcite data enum sql: " + querySQL);

View File

@ -262,6 +262,9 @@ public class DatasetGroupManage {
List<CoreDatasetTable> coreDatasetTables = coreDatasetTableMapper.selectList(wrapper);
Set<Long> ids = new LinkedHashSet();
coreDatasetTables.forEach(ele -> ids.add(ele.getDatasourceId()));
if (CollectionUtils.isEmpty(ids)) {
DEException.throwException("数据集因异常导致无法使用,请重新创建");
}
QueryWrapper<CoreDatasource> datasourceQueryWrapper = new QueryWrapper<>();
datasourceQueryWrapper.in("id", ids);
@ -559,6 +562,9 @@ public class DatasetGroupManage {
return;
}
fullName.add(parent.getName());
if (parent.getId().equals(parent.getPid())) {
return;
}
if (parent.getPid() != null && parent.getPid() != 0) {
geFullName(parent.getPid(), fullName);
}

View File

@ -71,7 +71,7 @@ public class DatasetSQLManage {
if (CollectionUtils.isEmpty(filterDTO.getValue())) {
continue;
}
filterParametersAdaptor(parameters,filterDTO,datasetTableId);
filterParametersAdaptor(parameters, filterDTO, datasetTableId);
}
}
if (chartExtRequest != null && ObjectUtils.isNotEmpty(chartExtRequest.getFilter())) {
@ -79,13 +79,13 @@ public class DatasetSQLManage {
if (CollectionUtils.isEmpty(filterDTO.getValue())) {
continue;
}
filterParametersAdaptor(parameters,filterDTO,datasetTableId);
filterParametersAdaptor(parameters, filterDTO, datasetTableId);
}
}
return parameters;
}
private void filterParametersAdaptor(List<SqlVariableDetails> parameters,ChartExtFilterDTO filterDTO,Long datasetTableId){
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)) {
@ -152,17 +152,22 @@ public class DatasetSQLManage {
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 {
DsTypeDTO datasourceType = getDatasourceType(dsMap, datasetTable.getDatasourceId());
prefix = datasourceType.getPrefix();
suffix = datasourceType.getSuffix();
}
}
return table.getTableAlias() + "." + prefix + f.getOriginName() + suffix + " AS " + prefix + alias + suffix;
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);
@ -488,6 +493,15 @@ public class DatasetSQLManage {
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 = coreDatasourceMapper.selectById(ds.getDatasourceId());
schemaAlias = String.format(SQLConstants.SCHEMA, coreDatasource.getId());
if (!dsMap.containsKey(coreDatasource.getId())) {
DatasourceSchemaDTO datasourceSchemaDTO = new DatasourceSchemaDTO();
BeanUtils.copyBean(datasourceSchemaDTO, coreDatasource);

View File

@ -0,0 +1,29 @@
package io.dataease.datasource.dto.es;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
@Data
public class EsResponse {
private List<Column> columns = new ArrayList<>();
private List<String[]> rows = new ArrayList<>();
private String cursor;
private Integer status;
private Error error;
private String version;
@Data
public class Error {
private String type;
private String reason;
}
@Data
public class Column {
private String name;
private String type;
}
}

View File

@ -0,0 +1,10 @@
package io.dataease.datasource.dto.es;
import lombok.Data;
@Data
public class Request {
private String query;
private Integer fetch_size = 10000;
private boolean field_multi_value_leniency = true;
}

View File

@ -0,0 +1,8 @@
package io.dataease.datasource.dto.es;
import lombok.Data;
@Data
public class RequestWithCursor extends Request {
private String cursor;
}

View File

@ -269,7 +269,7 @@ public class CalciteProvider extends Provider {
try (Connection con = getConnectionFromPool(datasourceRequest.getDatasource().getId()); Statement statement = getStatement(con, 30)) {
datasourceRequest.setDsVersion(con.getMetaData().getDatabaseMajorVersion());
if (datasourceRequest.getDatasource().getType().equalsIgnoreCase("mongo") || isDorisCatalog(datasourceRequest)) {
resultSet = statement.executeQuery("select * from " + table + " limit 0 offset 0 ");
resultSet = statement.executeQuery("select * from " + String.format(" `%s`", table) + " limit 0 offset 0 ");
return fetchResultField(resultSet);
}
resultSet = statement.executeQuery(getTableFiledSql(datasourceRequest));
@ -777,135 +777,176 @@ public class CalciteProvider extends Provider {
case StarRocks:
case doris:
configuration = JsonUtil.parseObject(ds.getConfiguration(), Mysql.class);
dataSource.setUrl(configuration.getJdbc());
dataSource.setUsername(configuration.getUsername());
dataSource.setPassword(configuration.getPassword());
if (StringUtils.isNotBlank(configuration.getUsername())) {
dataSource.setUsername(configuration.getUsername());
}
if (StringUtils.isNotBlank(configuration.getPassword())) {
dataSource.setPassword(configuration.getPassword());
}
dataSource.setDefaultQueryTimeout(Integer.valueOf(configuration.getQueryTimeout()));
dataSource.setInitialSize(configuration.getInitialPoolSize());
dataSource.setMaxTotal(configuration.getMaxPoolSize());
dataSource.setMinIdle(configuration.getMinPoolSize());
startSshSession(configuration, null, ds.getId());
dataSource.setUrl(configuration.getJdbc());
schema = JdbcSchema.create(rootSchema, ds.getSchemaAlias(), dataSource, null, configuration.getDataBase());
rootSchema.add(ds.getSchemaAlias(), schema);
break;
case impala:
configuration = JsonUtil.parseObject(ds.getConfiguration(), Impala.class);
dataSource.setUrl(configuration.getJdbc());
dataSource.setUsername(configuration.getUsername());
dataSource.setPassword(configuration.getPassword());
if (StringUtils.isNotBlank(configuration.getUsername())) {
dataSource.setUsername(configuration.getUsername());
}
if (StringUtils.isNotBlank(configuration.getPassword())) {
dataSource.setPassword(configuration.getPassword());
}
dataSource.setInitialSize(configuration.getInitialPoolSize());
dataSource.setMaxTotal(configuration.getMaxPoolSize());
dataSource.setMinIdle(configuration.getMinPoolSize());
dataSource.setDefaultQueryTimeout(Integer.valueOf(configuration.getQueryTimeout()));
startSshSession(configuration, null, ds.getId());
dataSource.setUrl(configuration.getJdbc());
schema = JdbcSchema.create(rootSchema, ds.getSchemaAlias(), dataSource, null, configuration.getDataBase());
rootSchema.add(ds.getSchemaAlias(), schema);
break;
case sqlServer:
configuration = JsonUtil.parseObject(ds.getConfiguration(), Sqlserver.class);
dataSource.setUrl(configuration.getJdbc());
dataSource.setUsername(configuration.getUsername());
dataSource.setPassword(configuration.getPassword());
if (StringUtils.isNotBlank(configuration.getUsername())) {
dataSource.setUsername(configuration.getUsername());
}
if (StringUtils.isNotBlank(configuration.getPassword())) {
dataSource.setPassword(configuration.getPassword());
}
dataSource.setInitialSize(configuration.getInitialPoolSize());
dataSource.setMaxTotal(configuration.getMaxPoolSize());
dataSource.setMinIdle(configuration.getMinPoolSize());
dataSource.setDefaultQueryTimeout(Integer.valueOf(configuration.getQueryTimeout()));
startSshSession(configuration, null, ds.getId());
dataSource.setUrl(configuration.getJdbc());
schema = JdbcSchema.create(rootSchema, ds.getSchemaAlias(), dataSource, null, configuration.getSchema());
rootSchema.add(ds.getSchemaAlias(), schema);
break;
case oracle:
configuration = JsonUtil.parseObject(ds.getConfiguration(), Oracle.class);
dataSource.setUrl(configuration.getJdbc());
dataSource.setUsername(configuration.getUsername());
dataSource.setPassword(configuration.getPassword());
if (StringUtils.isNotBlank(configuration.getUsername())) {
dataSource.setUsername(configuration.getUsername());
}
if (StringUtils.isNotBlank(configuration.getPassword())) {
dataSource.setPassword(configuration.getPassword());
}
dataSource.setInitialSize(configuration.getInitialPoolSize());
dataSource.setMaxTotal(configuration.getMaxPoolSize());
dataSource.setMinIdle(configuration.getMinPoolSize());
dataSource.setDefaultQueryTimeout(Integer.valueOf(configuration.getQueryTimeout()));
startSshSession(configuration, null, ds.getId());
dataSource.setUrl(configuration.getJdbc());
schema = JdbcSchema.create(rootSchema, ds.getSchemaAlias(), dataSource, null, configuration.getSchema());
rootSchema.add(ds.getSchemaAlias(), schema);
break;
case db2:
configuration = JsonUtil.parseObject(ds.getConfiguration(), Db2.class);
dataSource.setUrl(configuration.getJdbc());
dataSource.setUsername(configuration.getUsername());
dataSource.setPassword(configuration.getPassword());
if (StringUtils.isNotBlank(configuration.getUsername())) {
dataSource.setUsername(configuration.getUsername());
}
if (StringUtils.isNotBlank(configuration.getPassword())) {
dataSource.setPassword(configuration.getPassword());
}
dataSource.setInitialSize(configuration.getInitialPoolSize());
dataSource.setMaxTotal(configuration.getMaxPoolSize());
dataSource.setMinIdle(configuration.getMinPoolSize());
dataSource.setDefaultQueryTimeout(Integer.valueOf(configuration.getQueryTimeout()));
startSshSession(configuration, null, ds.getId());
dataSource.setUrl(configuration.getJdbc());
schema = JdbcSchema.create(rootSchema, ds.getSchemaAlias(), dataSource, null, configuration.getSchema());
rootSchema.add(ds.getSchemaAlias(), schema);
break;
case ck:
configuration = JsonUtil.parseObject(ds.getConfiguration(), CK.class);
dataSource.setUrl(configuration.getJdbc());
dataSource.setUsername(configuration.getUsername());
dataSource.setPassword(configuration.getPassword());
if (StringUtils.isNotBlank(configuration.getUsername())) {
dataSource.setUsername(configuration.getUsername());
}
if (StringUtils.isNotBlank(configuration.getPassword())) {
dataSource.setPassword(configuration.getPassword());
}
dataSource.setInitialSize(configuration.getInitialPoolSize());
dataSource.setMaxTotal(configuration.getMaxPoolSize());
dataSource.setMinIdle(configuration.getMinPoolSize());
dataSource.setDefaultQueryTimeout(Integer.valueOf(configuration.getQueryTimeout()));
startSshSession(configuration, null, ds.getId());
dataSource.setUrl(configuration.getJdbc());
schema = JdbcSchema.create(rootSchema, ds.getSchemaAlias(), dataSource, null, configuration.getDataBase());
rootSchema.add(ds.getSchemaAlias(), schema);
break;
case pg:
configuration = JsonUtil.parseObject(ds.getConfiguration(), Pg.class);
dataSource.setUrl(configuration.getJdbc());
dataSource.setUsername(configuration.getUsername());
dataSource.setPassword(configuration.getPassword());
if (StringUtils.isNotBlank(configuration.getUsername())) {
dataSource.setUsername(configuration.getUsername());
}
if (StringUtils.isNotBlank(configuration.getPassword())) {
dataSource.setPassword(configuration.getPassword());
}
dataSource.setInitialSize(configuration.getInitialPoolSize());
dataSource.setMaxTotal(configuration.getMaxPoolSize());
dataSource.setMinIdle(configuration.getMinPoolSize());
dataSource.setDefaultQueryTimeout(Integer.valueOf(configuration.getQueryTimeout()));
startSshSession(configuration, null, ds.getId());
dataSource.setUrl(configuration.getJdbc());
schema = JdbcSchema.create(rootSchema, ds.getSchemaAlias(), dataSource, null, configuration.getSchema());
rootSchema.add(ds.getSchemaAlias(), schema);
break;
case redshift:
configuration = JsonUtil.parseObject(ds.getConfiguration(), Redshift.class);
dataSource.setUrl(configuration.getJdbc());
dataSource.setUsername(configuration.getUsername());
dataSource.setPassword(configuration.getPassword());
if (StringUtils.isNotBlank(configuration.getUsername())) {
dataSource.setUsername(configuration.getUsername());
}
if (StringUtils.isNotBlank(configuration.getPassword())) {
dataSource.setPassword(configuration.getPassword());
}
dataSource.setInitialSize(configuration.getInitialPoolSize());
dataSource.setMaxTotal(configuration.getMaxPoolSize());
dataSource.setMinIdle(configuration.getMinPoolSize());
dataSource.setDefaultQueryTimeout(Integer.valueOf(configuration.getQueryTimeout()));
startSshSession(configuration, null, ds.getId());
dataSource.setUrl(configuration.getJdbc());
schema = JdbcSchema.create(rootSchema, ds.getSchemaAlias(), dataSource, null, configuration.getSchema());
rootSchema.add(ds.getSchemaAlias(), schema);
break;
case h2:
configuration = JsonUtil.parseObject(ds.getConfiguration(), H2.class);
dataSource.setUrl(configuration.getJdbc());
dataSource.setUsername(configuration.getUsername());
dataSource.setPassword(configuration.getPassword());
if (StringUtils.isNotBlank(configuration.getUsername())) {
dataSource.setUsername(configuration.getUsername());
}
if (StringUtils.isNotBlank(configuration.getPassword())) {
dataSource.setPassword(configuration.getPassword());
}
dataSource.setInitialSize(configuration.getInitialPoolSize());
dataSource.setMaxTotal(configuration.getMaxPoolSize());
dataSource.setMinIdle(configuration.getMinPoolSize());
dataSource.setDefaultQueryTimeout(Integer.valueOf(configuration.getQueryTimeout()));
startSshSession(configuration, null, ds.getId());
dataSource.setUrl(configuration.getJdbc());
schema = JdbcSchema.create(rootSchema, ds.getSchemaAlias(), dataSource, null, configuration.getDataBase());
rootSchema.add(ds.getSchemaAlias(), schema);
break;
default:
configuration = JsonUtil.parseObject(ds.getConfiguration(), Mysql.class);
dataSource.setUrl(configuration.getJdbc());
dataSource.setUsername(configuration.getUsername());
dataSource.setPassword(configuration.getPassword());
if (StringUtils.isNotBlank(configuration.getUsername())) {
dataSource.setUsername(configuration.getUsername());
}
if (StringUtils.isNotBlank(configuration.getPassword())) {
dataSource.setPassword(configuration.getPassword());
}
dataSource.setInitialSize(configuration.getInitialPoolSize());
dataSource.setMaxTotal(configuration.getMaxPoolSize());
dataSource.setMinIdle(configuration.getMinPoolSize());
dataSource.setDefaultQueryTimeout(Integer.valueOf(configuration.getQueryTimeout()));
startSshSession(configuration, null, ds.getId());
dataSource.setUrl(configuration.getJdbc());
schema = JdbcSchema.create(rootSchema, ds.getSchemaAlias(), dataSource, null, configuration.getDataBase());
rootSchema.add(ds.getSchemaAlias(), schema);
}
} catch (Exception e) {
LogUtil.error("Fail to create connection: " + ds.getName(), e);
}
} catch (Exception e) {
}
@ -1345,13 +1386,21 @@ public class CalciteProvider extends Provider {
return connection;
}
private Connection getConnectionFromPool(Long dsId) throws SQLException {
Connection connection = take();
CalciteConnection calciteConnection = connection.unwrap(CalciteConnection.class);
SchemaPlus rootSchema = calciteConnection.getRootSchema();
JdbcSchema jdbcSchema = rootSchema.getSubSchema(String.format(SQLConstants.SCHEMA, dsId)).unwrap(JdbcSchema.class);
BasicDataSource basicDataSource = (BasicDataSource) jdbcSchema.getDataSource();
return basicDataSource.getConnection();
private Connection getConnectionFromPool(Long dsId) {
try {
Connection connection = take();
CalciteConnection calciteConnection = connection.unwrap(CalciteConnection.class);
SchemaPlus rootSchema = calciteConnection.getRootSchema();
if (rootSchema.getSubSchema(String.format(SQLConstants.SCHEMA, dsId)) == null) {
DEException.throwException("请检查数据源的有效性!");
}
JdbcSchema jdbcSchema = rootSchema.getSubSchema(String.format(SQLConstants.SCHEMA, dsId)).unwrap(JdbcSchema.class);
BasicDataSource basicDataSource = (BasicDataSource) jdbcSchema.getDataSource();
return basicDataSource.getConnection();
} catch (Exception e) {
DEException.throwException("连接无效, " + e.getMessage());
}
return null;
}
public void exec(EngineRequest engineRequest) throws Exception {

View File

@ -0,0 +1,217 @@
package io.dataease.datasource.provider;
import com.google.gson.Gson;
import com.google.gson.JsonParser;
import io.dataease.dataset.utils.FieldUtils;
import io.dataease.datasource.dto.es.EsResponse;
import io.dataease.datasource.dto.es.Request;
import io.dataease.datasource.type.Es;
import io.dataease.exception.DEException;
import io.dataease.extensions.datasource.dto.*;
import io.dataease.extensions.datasource.provider.Provider;
import io.dataease.i18n.Translator;
import io.dataease.utils.HttpClientConfig;
import io.dataease.utils.HttpClientUtil;
import io.dataease.utils.JsonUtil;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpHeaders;
import org.springframework.stereotype.Service;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;
@Service("esProvider")
public class EsProvider extends Provider {
@Override
public List<String> getSchema(DatasourceRequest datasourceRequest) {
return new ArrayList<>();
}
@Override
public List<DatasetTableDTO> getTables(DatasourceRequest datasourceRequest) {
List<DatasetTableDTO> tables = new ArrayList<>();
try {
String response = execQuery(datasourceRequest, "show tables", "?format=json");
tables = fetchTables(response);
tables = tables.stream().filter(table -> StringUtils.isNotEmpty(table.getTableName()) && !table.getTableName().startsWith(".")).collect(Collectors.toList());
tables.forEach(table -> {
table.setDatasourceId(datasourceRequest.getDatasource().getId());
});
} catch (Exception e) {
e.getMessage();
DEException.throwException(e);
}
return tables;
}
@Override
public ConnectionObj getConnection(DatasourceDTO coreDatasource) throws Exception {
return null;
}
@Override
public String checkStatus(DatasourceRequest datasourceRequest) throws Exception {
Es es = JsonUtil.parseObject(datasourceRequest.getDatasource().getConfiguration(), Es.class);
String response = execGetQuery(datasourceRequest);
if (JsonParser.parseString(response).getAsJsonObject().getAsJsonObject("error") != null) {
throw new Exception(JsonParser.parseString(response).getAsJsonObject().getAsJsonObject("error").get("reason").getAsString());
}
String version = JsonParser.parseString(response).getAsJsonObject().getAsJsonObject("version").get("number").getAsString();
String[] versionList = version.split("\\.");
if (Integer.valueOf(versionList[0]) < 7 && Integer.valueOf(versionList[1]) < 3) {
throw new Exception(Translator.get("i18n_es_limit"));
}
if (Integer.valueOf(versionList[0]) == 6) {
es.setUri("_xpack/sql");
}
if (Integer.valueOf(versionList[0]) > 6) {
es.setUri("_sql");
}
datasourceRequest.getDatasource().setConfiguration(JsonUtil.toJSONString(es).toString());
getTables(datasourceRequest);
return "Success";
}
@Override
public Map<String, Object> fetchResultField(DatasourceRequest datasourceRequest) {
Map<String, Object> result = new HashMap<>();
try {
String response = execQuery(datasourceRequest, datasourceRequest.getQuery(), "?format=json");
result.put("data", fetchResultData(response));
result.put("fields", fetchResultField4Sql(response));
} catch (Exception e) {
e.printStackTrace();
DEException.throwException(e);
}
return result;
}
@Override
public List<TableField> fetchTableField(DatasourceRequest datasourceRequest) {
List<TableField> tableFields = new ArrayList<>();
try {
String sql;
if (datasourceRequest.getTable() != null) {
sql = "select * from " + datasourceRequest.getTable() + " limit 0";
} else {
sql = datasourceRequest.getQuery();
}
String response = execQuery(datasourceRequest, sql, "?format=json");
tableFields = fetchResultField4Sql(response);
} catch (Exception e) {
DEException.throwException(e);
}
return tableFields;
}
@Override
public void hidePW(DatasourceDTO datasourceDTO) {
}
private List<String[]> fetchResultData(String response) throws Exception {
EsResponse esResponse = new Gson().fromJson(response, EsResponse.class);
return fetchResultData(esResponse);
}
private List<String[]> fetchResultData(EsResponse esResponse) throws Exception {
List<String[]> list = new LinkedList<>();
if (esResponse.getError() != null) {
throw new Exception(esResponse.getError().getReason());
}
list.addAll(esResponse.getRows());
return list;
}
private List<TableField> fetchResultField4Sql(String response) throws Exception {
List<TableField> fieldList = new ArrayList<>();
EsResponse esResponse = new Gson().fromJson(response, EsResponse.class);
if (esResponse.getError() != null) {
throw new Exception(esResponse.getError().getReason());
}
for (EsResponse.Column column : esResponse.getColumns()) {
TableField field = new TableField();
field.setOriginName(column.getName());
field.setOriginName(column.getName());
field.setFieldType(column.getType());
field.setType(column.getType().toUpperCase());
field.setFieldType(field.getType());
int deType = FieldUtils.transType2DeType(field.getType());
field.setDeExtractType(deType);
field.setDeType(deType);
fieldList.add(field);
}
return fieldList;
}
private List<DatasetTableDTO> fetchTables(String response) throws Exception {
List<DatasetTableDTO> tables = new ArrayList<>();
EsResponse esResponse = new Gson().fromJson(response, EsResponse.class);
if (esResponse.getError() != null) {
throw new Exception(esResponse.getError().getReason());
}
for (String[] row : esResponse.getRows()) {
DatasetTableDTO tableDesc = new DatasetTableDTO();
if (row.length == 3 && row[1].contains("TABLE") && row[2].equalsIgnoreCase("INDEX")) {
tableDesc.setTableName(row[0]);
}
if (row.length == 2 && row[1].contains("TABLE")) {
tableDesc.setTableName(row[0]);
}
if (row.length == 4 && row[2].contains("TABLE") && row[3].equalsIgnoreCase("INDEX")) {
tableDesc.setTableName(row[1]);
}
tableDesc.setType("es");
tables.add(tableDesc);
}
return tables;
}
private String execQuery(DatasourceRequest datasourceRequest, String sql, String uri) {
Es es = null;
if (datasourceRequest.getDatasource() == null) {
Collection<DatasourceSchemaDTO> datasourceSchemaDTOS = datasourceRequest.getDsList().values();
es = JsonUtil.parseObject(datasourceSchemaDTOS.stream().findFirst().get().getConfiguration(), Es.class);
} else {
es = JsonUtil.parseObject(datasourceRequest.getDatasource().getConfiguration(), Es.class);
}
uri = es.getUri() + uri;
HttpClientConfig httpClientConfig = new HttpClientConfig();
if (StringUtils.isNotEmpty(es.getUsername()) && StringUtils.isNotEmpty(es.getPassword())) {
String auth = es.getUsername() + ":" + es.getPassword();
byte[] encodedAuth = Base64.encodeBase64(auth.getBytes(StandardCharsets.UTF_8));
httpClientConfig.addHeader(HttpHeaders.AUTHORIZATION, "Basic " + new String(encodedAuth));
}
Request request = new Request();
request.setQuery(sql);
request.setFetch_size(datasourceRequest.getFetchSize());
String url = es.getUrl().endsWith("/") ? es.getUrl() + uri : es.getUrl() + "/" + uri;
return HttpClientUtil.post(url, new Gson().toJson(request), httpClientConfig);
}
private String execGetQuery(DatasourceRequest datasourceRequest) {
Es es = JsonUtil.parseObject(datasourceRequest.getDatasource().getConfiguration(), Es.class);
HttpClientConfig httpClientConfig = new HttpClientConfig();
if (StringUtils.isNotEmpty(es.getUsername()) && StringUtils.isNotEmpty(es.getPassword())) {
String auth = es.getUsername() + ":" + es.getPassword();
byte[] encodedAuth = Base64.encodeBase64(auth.getBytes(StandardCharsets.UTF_8));
httpClientConfig.addHeader(HttpHeaders.AUTHORIZATION, "Basic " + new String(encodedAuth));
}
return HttpClientUtil.get(es.getUrl(), httpClientConfig);
}
}

View File

@ -15,6 +15,7 @@ import io.dataease.api.ds.vo.ExcelSheetData;
import io.dataease.datasource.dao.auto.entity.CoreDatasource;
import io.dataease.exception.DEException;
import io.dataease.extensions.datasource.dto.DatasetTableDTO;
import io.dataease.extensions.datasource.dto.DatasourceDTO;
import io.dataease.extensions.datasource.dto.DatasourceRequest;
import io.dataease.extensions.datasource.dto.TableField;
import io.dataease.utils.AuthUtils;
@ -40,6 +41,21 @@ public class ExcelUtils {
private static TypeReference<List<TableField>> TableFieldListTypeReference = new TypeReference<List<TableField>>() {
};
private static TypeReference<List<ExcelSheetData>> sheets = new TypeReference<List<ExcelSheetData>>() {
};
public static void mergeSheets(CoreDatasource requestDatasource, DatasourceDTO sourceData) {
List<ExcelSheetData> newSheets = JsonUtil.parseList(requestDatasource.getConfiguration(), sheets);
List<String> tableNames = newSheets.stream().map(ExcelSheetData::getDeTableName).collect(Collectors.toList());
List<ExcelSheetData> oldSheets = JsonUtil.parseList(sourceData.getConfiguration(), sheets);
for (ExcelSheetData oldSheet : oldSheets) {
if (!tableNames.contains(oldSheet.getDeTableName())) {
newSheets.add(oldSheet);
}
}
requestDatasource.setConfiguration(JsonUtil.toJSONString(newSheets).toString());
}
public static List<DatasetTableDTO> getTables(DatasourceRequest datasourceRequest) throws DEException {
List<DatasetTableDTO> tableDescs = new ArrayList<>();
try {
@ -311,7 +327,7 @@ public class ExcelUtils {
if (StringUtils.isEmpty(value) || value.length() > 19) {
return "TEXT";
}
String regex = "^\\d+(\\.\\d+)?$";
String regex = "^-?\\d+(\\.\\d+)?$";
if (!value.matches(regex)) {
return "TEXT";
}

View File

@ -84,15 +84,10 @@ public class H2EngineProvider extends EngineProvider {
int size = tableField.getPrecision() * 4;
switch (tableField.getDeType()) {
case 0:
Column_Fields.append("longtext").append(",`");
Column_Fields.append("varchar(2048)").append(",`");
break;
case 1:
size = size < 50 ? 50 : size;
if (size < 65533) {
Column_Fields.append("varchar(length)".replace("length", String.valueOf(tableField.getPrecision()))).append(",`");
} else {
Column_Fields.append("longtext").append(",`");
}
Column_Fields.append("varchar(2048)").append(",`");
break;
case 2:
Column_Fields.append("bigint(20)").append(",`");
@ -104,11 +99,7 @@ public class H2EngineProvider extends EngineProvider {
Column_Fields.append("TINYINT(length)".replace("length", String.valueOf(tableField.getPrecision()))).append(",`");
break;
default:
if (size < 65533) {
Column_Fields.append("varchar(length)".replace("length", String.valueOf(tableField.getPrecision()))).append(",`");
} else {
Column_Fields.append("longtext").append(",`");
}
Column_Fields.append("varchar(2048)").append(",`");
break;
}
}

View File

@ -89,7 +89,7 @@ public class MysqlEngineProvider extends EngineProvider {
int size = tableField.getPrecision() * 4;
switch (tableField.getDeExtractType()) {
case 0:
Column_Fields.append("longtext").append(",`");
Column_Fields.append("varchar(1024)").append(",`");
break;
case 1:
Column_Fields.append("datetime").append(",`");
@ -104,7 +104,7 @@ public class MysqlEngineProvider extends EngineProvider {
Column_Fields.append("TINYINT(length)".replace("length", String.valueOf(tableField.getPrecision()))).append(",`");
break;
default:
Column_Fields.append("longtext").append(",`");
Column_Fields.append("varchar(1024)").append(",`");
break;
}
}

View File

@ -126,7 +126,7 @@ public class DatasourceServer implements DatasourceApi {
}
public boolean checkRepeat(@RequestBody BusiDsRequest dataSourceDTO) {
if (Arrays.asList("API", "Excel", "folder").contains(dataSourceDTO.getType())) {
if (Arrays.asList("API", "Excel", "folder", "es").contains(dataSourceDTO.getType())) {
return false;
}
BusiNodeRequest request = new BusiNodeRequest();
@ -267,7 +267,11 @@ public class DatasourceServer implements DatasourceApi {
try {
datasourceSyncManage.createEngineTable(datasourceRequest.getTable(), tableFields);
} catch (Exception e) {
DEException.throwException("Failed to create table " + datasourceRequest.getTable() + ", " + e.getMessage());
if (e.getMessage().toLowerCase().contains("Row size too large".toLowerCase())) {
DEException.throwException("文本内容超出最大支持范围: " + datasourceRequest.getTable() + ", " + e.getMessage());
} else {
DEException.throwException("Failed to create table " + datasourceRequest.getTable() + ", " + e.getMessage());
}
}
}
commonThreadPool.addTask(() -> {
@ -404,7 +408,7 @@ public class DatasourceServer implements DatasourceApi {
List<String> tables = ExcelUtils.getTables(datasourceRequest).stream().map(DatasetTableDTO::getTableName).collect(Collectors.toList());
if (dataSourceDTO.getEditType() == 0) {
toCreateTables = tables;
toDeleteTables = sourceTables;
toDeleteTables = sourceTables.stream().filter(s -> tables.contains(s)).collect(Collectors.toList());
for (String deleteTable : toDeleteTables) {
try {
datasourceSyncManage.dropEngineTable(deleteTable);
@ -422,6 +426,7 @@ public class DatasourceServer implements DatasourceApi {
}
datasourceSyncManage.extractExcelData(requestDatasource, "all_scope");
dataSourceManage.checkName(dataSourceDTO);
ExcelUtils.mergeSheets(requestDatasource, sourceData);
dataSourceManage.innerEdit(requestDatasource);
} else {
datasourceSyncManage.extractExcelData(requestDatasource, "add_scope");
@ -488,6 +493,15 @@ public class DatasourceServer implements DatasourceApi {
return getDatasourceDTOById(datasourceId, false);
}
@Override
public String getName(Long datasourceId) throws DEException {
CoreDatasource datasource = datasourceMapper.selectById(datasourceId);
if (datasource == null) {
DEException.throwException("不存在的数据源!");
}
return datasource.getName();
}
@Override
public List<DatasourceDTO> innerList(List<Long> ids, List<String> types) throws DEException {
List<DatasourceDTO> list = new ArrayList<>();
@ -726,11 +740,15 @@ public class DatasourceServer implements DatasourceApi {
}
}
private static final Integer replace = 0;
private static final Integer append = 1;
public ExcelFileData excelUpload(@RequestParam("file") MultipartFile file, @RequestParam("id") long datasourceId, @RequestParam("editType") Integer editType) throws DEException {
CoreDatasource coreDatasource = datasourceMapper.selectById(datasourceId);
ExcelUtils excelUtils = new ExcelUtils();
ExcelFileData excelFileData = excelUtils.excelSaveAndParse(file);
if (editType == 1 || editType == 0) { //按照excel sheet 名称匹配
CoreDatasource coreDatasource = datasourceMapper.selectById(datasourceId);
if (Objects.equals(editType, append)) { //按照excel sheet 名称匹配替换0追加1
if (coreDatasource != null) {
DatasourceRequest datasourceRequest = new DatasourceRequest();
datasourceRequest.setDatasource(transDTO(coreDatasource));
@ -748,7 +766,6 @@ public class DatasourceServer implements DatasourceApi {
oldTableFields.sort((o1, o2) -> {
return o1.getName().compareTo(o2.getName());
});
if (isEqual(newTableFields, oldTableFields)) {
sheet.setDeTableName(datasetTableDTO.getTableName());
excelSheetDataList.add(sheet);
@ -761,8 +778,21 @@ public class DatasourceServer implements DatasourceApi {
}
excelFileData.setSheets(excelSheetDataList);
}
}
} else {
if (coreDatasource != null) {
DatasourceRequest datasourceRequest = new DatasourceRequest();
datasourceRequest.setDatasource(transDTO(coreDatasource));
List<DatasetTableDTO> datasetTableDTOS = ExcelUtils.getTables(datasourceRequest);
for (ExcelSheetData sheet : excelFileData.getSheets()) {
for (DatasetTableDTO datasetTableDTO : datasetTableDTOS) {
if (excelDataTableName(datasetTableDTO.getTableName()).equals(sheet.getTableName()) || isCsv(file.getOriginalFilename())) {
sheet.setDeTableName(datasetTableDTO.getTableName());
}
}
}
}
}
for (ExcelSheetData sheet : excelFileData.getSheets()) {
for (int i = 0; i < sheet.getFields().size() - 1; i++) {
for (int j = i + 1; j < sheet.getFields().size(); j++) {
@ -1146,8 +1176,11 @@ public class DatasourceServer implements DatasourceApi {
if (!Arrays.asList("API", "Excel", "folder").contains(coreDatasource.getType())) {
calciteProvider.updateDsPoolAfterCheckStatus(datasourceDTO);
}
} catch (DEException e) {
datasourceDTO.setStatus("Error");
DEException.throwException(e.getMessage());
} catch (Exception e) {
coreDatasource.setStatus("Error");
datasourceDTO.setStatus("Error");
DEException.throwException(e.getMessage());
} finally {
coreDatasource.setStatus(datasourceDTO.getStatus());

View File

@ -0,0 +1,15 @@
package io.dataease.datasource.type;
import lombok.Data;
import org.springframework.stereotype.Component;
@Data
public class Es {
private String url;
private String username;
private String password;
private String version;
private String uri;
}

View File

@ -71,6 +71,8 @@ public class SQLConstants {
public static final String WHERE_VALUE_VALUE = "'%s'";
public static final String WHERE_VALUE_VALUE_CH = "'-DENS-%s'";
public static final String WHERE_NUMBER_VALUE = "%s";
public static final String AGG_COUNT = "COUNT(*)";
@ -96,4 +98,6 @@ public class SQLConstants {
public static final String EMPTY_SIGN = "_empty_$";
public static final String CONCAT = "CONCAT(%s, %s)";
public static final String MSSQL_N_PREFIX = "-DENS-";
}

View File

@ -17,6 +17,7 @@ import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import java.util.*;
import java.util.stream.Collectors;
/**
* @Author Junjun
@ -77,6 +78,13 @@ public class CustomWhere2Str {
if (ObjectUtils.isEmpty(field)) {
return null;
}
String dsType = null;
if (dsMap != null && dsMap.entrySet().iterator().hasNext()) {
Map.Entry<Long, DatasourceSchemaDTO> next = dsMap.entrySet().iterator().next();
dsType = next.getValue().getType();
}
Map<String, String> paramMap = Utils.mergeParam(fieldParam, chartParam);
String whereName = "";
String originName;
@ -90,9 +98,17 @@ public class CustomWhere2Str {
originName = calcFieldExp;
}
} else if (ObjectUtils.isNotEmpty(field.getExtField()) && field.getExtField() == 1) {
originName = String.format(SQLConstants.FIELD_NAME, tableObj.getTableAlias(), field.getDataeaseName());
if (StringUtils.equalsIgnoreCase(dsType, "es")) {
originName = String.format(SQLConstants.FIELD_NAME, tableObj.getTableAlias(), field.getOriginName());
} else {
originName = String.format(SQLConstants.FIELD_NAME, tableObj.getTableAlias(), field.getDataeaseName());
}
} else {
originName = String.format(SQLConstants.FIELD_NAME, tableObj.getTableAlias(), field.getDataeaseName());
if (StringUtils.equalsIgnoreCase(dsType, "es")) {
originName = String.format(SQLConstants.FIELD_NAME, tableObj.getTableAlias(), field.getOriginName());
} else {
originName = String.format(SQLConstants.FIELD_NAME, tableObj.getTableAlias(), field.getDataeaseName());
}
}
if (field.getDeType() == 1) {
if (field.getDeExtractType() == 0 || field.getDeExtractType() == 5) {
@ -114,7 +130,14 @@ public class CustomWhere2Str {
}
}
// 此处获取标准格式的日期
whereName = originName;
if (StringUtils.equalsIgnoreCase(field.getType(), "date")
|| (StringUtils.equalsIgnoreCase(dsMap.entrySet().iterator().next().getValue().getType(), "oracle") && StringUtils.equalsIgnoreCase(field.getType(), "timestamp"))) {
whereName = String.format(SQLConstants.DE_CAST_DATE_FORMAT, originName,
SQLConstants.DEFAULT_DATE_FORMAT,
SQLConstants.DEFAULT_DATE_FORMAT);
} else {
whereName = originName;
}
}
} else if (field.getDeType() == 2 || field.getDeType() == 3) {
if (field.getDeExtractType() == 0 || field.getDeExtractType() == 5) {
@ -135,7 +158,12 @@ public class CustomWhere2Str {
if (StringUtils.equalsIgnoreCase(item.getFilterType(), "enum")) {
if (ObjectUtils.isNotEmpty(item.getEnumValue())) {
res = "(" + whereName + " IN ('" + String.join("','", item.getEnumValue()) + "'))";
if (StringUtils.containsIgnoreCase(field.getType(), "NVARCHAR")
|| StringUtils.containsIgnoreCase(field.getType(), "NCHAR")) {
res = "(" + whereName + " IN (" + item.getEnumValue().stream().map(str -> "'" + SQLConstants.MSSQL_N_PREFIX + str + "'").collect(Collectors.joining(",")) + "))";
} else {
res = "(" + whereName + " IN ('" + String.join("','", item.getEnumValue()) + "'))";
}
}
} else {
if (field.getDeType() == 1 && isCross) {
@ -156,9 +184,19 @@ public class CustomWhere2Str {
} 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(",")) + "')";
if (StringUtils.containsIgnoreCase(field.getType(), "NVARCHAR")
|| StringUtils.containsIgnoreCase(field.getType(), "NCHAR")) {
whereValue = "(" + Arrays.stream(value.split(",")).map(str -> "'" + SQLConstants.MSSQL_N_PREFIX + str + "'").collect(Collectors.joining(",")) + ")";
} else {
whereValue = "('" + String.join("','", value.split(",")) + "')";
}
} else if (StringUtils.containsIgnoreCase(item.getTerm(), "like")) {
whereValue = "'%" + value + "%'";
if (StringUtils.containsIgnoreCase(field.getType(), "NVARCHAR")
|| StringUtils.containsIgnoreCase(field.getType(), "NCHAR")) {
whereValue = "'" + SQLConstants.MSSQL_N_PREFIX + "%" + value + "%'";
} else {
whereValue = "'%" + value + "%'";
}
} else {
// 如果是时间字段过滤当条件是等于和不等于的时候转换成between和not between
if (field.getDeType() == 1) {
@ -199,7 +237,12 @@ public class CustomWhere2Str {
whereValue = String.format(SQLConstants.WHERE_VALUE_VALUE, value);
}
} else {
whereValue = String.format(SQLConstants.WHERE_VALUE_VALUE, value);
if (StringUtils.containsIgnoreCase(field.getType(), "NVARCHAR")
|| StringUtils.containsIgnoreCase(field.getType(), "NCHAR")) {
whereValue = String.format(SQLConstants.WHERE_VALUE_VALUE_CH, value);
} else {
whereValue = String.format(SQLConstants.WHERE_VALUE_VALUE, value);
}
}
}
SQLObj build = SQLObj.builder()

View File

@ -33,13 +33,20 @@ public class Dimension2SQLObj {
List<SQLObj> xFields = new ArrayList<>();
List<SQLObj> xOrders = new ArrayList<>();
Map<String, String> fieldsDialect = new HashMap<>();
String dsType = null;
if (dsMap != null && dsMap.entrySet().iterator().hasNext()) {
Map.Entry<Long, DatasourceSchemaDTO> next = dsMap.entrySet().iterator().next();
dsType = next.getValue().getType();
}
if (!CollectionUtils.isEmpty(fields)) {
for (int i = 0; i < fields.size(); i++) {
ChartViewFieldDTO x = fields.get(i);
String originField;
if (ObjectUtils.isNotEmpty(x.getExtField()) && Objects.equals(x.getExtField(), ExtFieldConstant.EXT_CALC)) {
// 解析origin name中有关联的字段生成sql表达式
String calcFieldExp = Utils.calcFieldRegex(x.getOriginName(), tableObj, originFields, isCross, dsMap, paramMap,pluginManage);
String calcFieldExp = Utils.calcFieldRegex(x.getOriginName(), tableObj, originFields, isCross, dsMap, paramMap, pluginManage);
// 给计算字段处加一个占位符后续SQL方言转换后再替换
originField = String.format(SqlPlaceholderConstants.CALC_FIELD_PLACEHOLDER, x.getId());
fieldsDialect.put(originField, calcFieldExp);
@ -47,9 +54,17 @@ public class Dimension2SQLObj {
originField = calcFieldExp;
}
} else if (ObjectUtils.isNotEmpty(x.getExtField()) && Objects.equals(x.getExtField(), ExtFieldConstant.EXT_COPY)) {
originField = String.format(SQLConstants.FIELD_NAME, tableObj.getTableAlias(), x.getDataeaseName());
if (StringUtils.equalsIgnoreCase(dsType, "es")) {
originField = String.format(SQLConstants.FIELD_NAME, tableObj.getTableAlias(), x.getOriginName());
} else {
originField = String.format(SQLConstants.FIELD_NAME, tableObj.getTableAlias(), x.getDataeaseName());
}
} else {
originField = String.format(SQLConstants.FIELD_NAME, tableObj.getTableAlias(), x.getDataeaseName());
if (StringUtils.equalsIgnoreCase(dsType, "es")) {
originField = String.format(SQLConstants.FIELD_NAME, tableObj.getTableAlias(), x.getOriginName());
} else {
originField = String.format(SQLConstants.FIELD_NAME, tableObj.getTableAlias(), x.getDataeaseName());
}
}
String fieldAlias = String.format(SQLConstants.FIELD_ALIAS_X_PREFIX, i);
// 处理横轴字段

View File

@ -17,6 +17,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* @Author Junjun
@ -31,6 +32,13 @@ public class ExtWhere2Str {
Map<String, String> paramMap = Utils.mergeParam(fieldParam, chartParam);
List<SQLObj> list = new ArrayList<>();
Map<String, String> fieldsDialect = new HashMap<>();
String dsType = null;
if (dsMap != null && dsMap.entrySet().iterator().hasNext()) {
Map.Entry<Long, DatasourceSchemaDTO> next = dsMap.entrySet().iterator().next();
dsType = next.getValue().getType();
}
if (ObjectUtils.isNotEmpty(fields)) {
for (ChartExtFilterDTO request : fields) {
List<String> value = request.getValue();
@ -60,9 +68,17 @@ public class ExtWhere2Str {
originName = calcFieldExp;
}
} else if (ObjectUtils.isNotEmpty(field.getExtField()) && field.getExtField() == 1) {
originName = String.format(SQLConstants.FIELD_NAME, tableObj.getTableAlias(), field.getDataeaseName());
if (StringUtils.equalsIgnoreCase(dsType, "es")) {
originName = String.format(SQLConstants.FIELD_NAME, tableObj.getTableAlias(), field.getOriginName());
} else {
originName = String.format(SQLConstants.FIELD_NAME, tableObj.getTableAlias(), field.getDataeaseName());
}
} else {
originName = String.format(SQLConstants.FIELD_NAME, tableObj.getTableAlias(), field.getDataeaseName());
if (StringUtils.equalsIgnoreCase(dsType, "es")) {
originName = String.format(SQLConstants.FIELD_NAME, tableObj.getTableAlias(), field.getOriginName());
} else {
originName = String.format(SQLConstants.FIELD_NAME, tableObj.getTableAlias(), field.getDataeaseName());
}
}
if (field.getDeType() == 1) {
@ -87,8 +103,10 @@ public class ExtWhere2Str {
originName = String.format(SQLConstants.DE_STR_TO_DATE, String.format(SQLConstants.CONCAT, "'1970-01-01 '", originName), SQLConstants.DEFAULT_DATE_FORMAT);
}
}
// 此处获取标准格式的日期
whereName = originName;
// 此处获取标准格式的日期同时此处是仪表板过滤仪表板中图表的日期均已经格式化所以要强制加上日期转换
whereName = String.format(SQLConstants.DE_CAST_DATE_FORMAT, originName,
SQLConstants.DEFAULT_DATE_FORMAT,
SQLConstants.DEFAULT_DATE_FORMAT);
}
} else if (field.getDeType() == 2 || field.getDeType() == 3) {
if (field.getDeExtractType() == 0 || field.getDeExtractType() == 5) {
@ -129,10 +147,56 @@ public class ExtWhere2Str {
if (value.contains(SQLConstants.EMPTY_SIGN)) {
whereValue = "('" + StringUtils.join(value, "','") + "', '')" + " or " + whereName + " is null ";
} else {
whereValue = "('" + StringUtils.join(value, "','") + "')";
// tree的情况需额外处理
if (request.getIsTree()) {
List<DatasetTableFieldDTO> datasetTableFieldList = request.getDatasetTableFieldList();
boolean hasN = false;
for (DatasetTableFieldDTO dto : datasetTableFieldList) {
if (StringUtils.containsIgnoreCase(dto.getType(), "NVARCHAR")
|| StringUtils.containsIgnoreCase(dto.getType(), "NCHAR")) {
hasN = true;
break;
}
}
if (hasN) {
whereValue = "(" + value.stream().map(str -> "'" + SQLConstants.MSSQL_N_PREFIX + str + "'").collect(Collectors.joining(",")) + ")";
} else {
whereValue = "('" + StringUtils.join(value, "','") + "')";
}
} else {
if (StringUtils.containsIgnoreCase(request.getDatasetTableField().getType(), "NVARCHAR")
|| StringUtils.containsIgnoreCase(request.getDatasetTableField().getType(), "NCHAR")) {
whereValue = "(" + value.stream().map(str -> "'" + SQLConstants.MSSQL_N_PREFIX + str + "'").collect(Collectors.joining(",")) + ")";
} else {
whereValue = "('" + StringUtils.join(value, "','") + "')";
}
}
}
} else if (StringUtils.containsIgnoreCase(request.getOperator(), "like")) {
whereValue = "'%" + value.get(0) + "%'";
// tree的情况需额外处理
if (request.getIsTree()) {
List<DatasetTableFieldDTO> datasetTableFieldList = request.getDatasetTableFieldList();
boolean hasN = false;
for (DatasetTableFieldDTO dto : datasetTableFieldList) {
if (StringUtils.containsIgnoreCase(dto.getType(), "NVARCHAR")
|| StringUtils.containsIgnoreCase(dto.getType(), "NCHAR")) {
hasN = true;
break;
}
}
if (hasN) {
whereValue = "'" + SQLConstants.MSSQL_N_PREFIX + "%" + value.get(0) + "%'";
} else {
whereValue = "'%" + value.get(0) + "%'";
}
} else {
if (StringUtils.containsIgnoreCase(request.getDatasetTableField().getType(), "NVARCHAR")
|| StringUtils.containsIgnoreCase(request.getDatasetTableField().getType(), "NCHAR")) {
whereValue = "'" + SQLConstants.MSSQL_N_PREFIX + "%" + value.get(0) + "%'";
} else {
whereValue = "'%" + value.get(0) + "%'";
}
}
} else if (StringUtils.containsIgnoreCase(request.getOperator(), "between")) {
if (request.getDatasetTableField().getDeType() == 1) {
if (request.getDatasetTableField().getDeExtractType() == 2
@ -151,6 +215,10 @@ public class ExtWhere2Str {
whereValue = String.format(SQLConstants.WHERE_BETWEEN, Utils.transLong2Str(Long.parseLong(value.get(0))), Utils.transLong2Str(Long.parseLong(value.get(1))));
}
}
} else if (request.getDatasetTableField().getDeType() == 2
|| request.getDatasetTableField().getDeType() == 3
|| request.getDatasetTableField().getDeType() == 4) {
whereValue = String.format(SQLConstants.WHERE_VALUE_BETWEEN, value.get(0), value.get(1));
} else {
whereValue = String.format(SQLConstants.WHERE_BETWEEN, value.get(0), value.get(1));
}
@ -159,7 +227,30 @@ public class ExtWhere2Str {
if (StringUtils.equals(value.get(0), SQLConstants.EMPTY_SIGN)) {
whereValue = String.format(SQLConstants.WHERE_VALUE_VALUE, "") + " or " + whereName + " is null ";
} else {
whereValue = String.format(SQLConstants.WHERE_VALUE_VALUE, value.get(0));
// tree的情况需额外处理
if (request.getIsTree()) {
List<DatasetTableFieldDTO> datasetTableFieldList = request.getDatasetTableFieldList();
boolean hasN = false;
for (DatasetTableFieldDTO dto : datasetTableFieldList) {
if (StringUtils.containsIgnoreCase(dto.getType(), "NVARCHAR")
|| StringUtils.containsIgnoreCase(dto.getType(), "NCHAR")) {
hasN = true;
break;
}
}
if (hasN) {
whereValue = String.format(SQLConstants.WHERE_VALUE_VALUE_CH, value.get(0));
} else {
whereValue = String.format(SQLConstants.WHERE_VALUE_VALUE, value.get(0));
}
} else {
if (StringUtils.containsIgnoreCase(request.getDatasetTableField().getType(), "NVARCHAR")
|| StringUtils.containsIgnoreCase(request.getDatasetTableField().getType(), "NCHAR")) {
whereValue = String.format(SQLConstants.WHERE_VALUE_VALUE_CH, value.get(0));
} else {
whereValue = String.format(SQLConstants.WHERE_VALUE_VALUE, value.get(0));
}
}
}
}
list.add(SQLObj.builder()

View File

@ -30,13 +30,20 @@ public class Field2SQLObj {
Map<String, String> paramMap = Utils.mergeParam(fieldParam, chartParam);
List<SQLObj> xFields = new ArrayList<>();
Map<String, String> fieldsDialect = new HashMap<>();
String dsType = null;
if (dsMap != null && dsMap.entrySet().iterator().hasNext()) {
Map.Entry<Long, DatasourceSchemaDTO> next = dsMap.entrySet().iterator().next();
dsType = next.getValue().getType();
}
if (ObjectUtils.isNotEmpty(fields)) {
for (int i = 0; i < fields.size(); i++) {
DatasetTableFieldDTO x = fields.get(i);
String originField;
if (ObjectUtils.isNotEmpty(x.getExtField()) && Objects.equals(x.getExtField(), ExtFieldConstant.EXT_CALC)) {
// 解析origin name中有关联的字段生成sql表达式
String calcFieldExp = Utils.calcFieldRegex(x.getOriginName(), tableObj, originFields, isCross, dsMap, paramMap,pluginManage);
String calcFieldExp = Utils.calcFieldRegex(x.getOriginName(), tableObj, originFields, isCross, dsMap, paramMap, pluginManage);
// 给计算字段处加一个占位符后续SQL方言转换后再替换
originField = String.format(SqlPlaceholderConstants.CALC_FIELD_PLACEHOLDER, x.getId());
fieldsDialect.put(originField, calcFieldExp);
@ -51,9 +58,17 @@ public class Field2SQLObj {
}
}
} else if (ObjectUtils.isNotEmpty(x.getExtField()) && Objects.equals(x.getExtField(), ExtFieldConstant.EXT_COPY)) {
originField = String.format(SQLConstants.FIELD_NAME, tableObj.getTableAlias(), x.getDataeaseName());
if (StringUtils.equalsIgnoreCase(dsType, "es")) {
originField = String.format(SQLConstants.FIELD_NAME, tableObj.getTableAlias(), x.getOriginName());
} else {
originField = String.format(SQLConstants.FIELD_NAME, tableObj.getTableAlias(), x.getDataeaseName());
}
} else {
originField = String.format(SQLConstants.FIELD_NAME, tableObj.getTableAlias(), x.getDataeaseName());
if (StringUtils.equalsIgnoreCase(dsType, "es")) {
originField = String.format(SQLConstants.FIELD_NAME, tableObj.getTableAlias(), x.getOriginName());
} else {
originField = String.format(SQLConstants.FIELD_NAME, tableObj.getTableAlias(), x.getDataeaseName());
}
}
String fieldAlias = String.format(SQLConstants.FIELD_ALIAS_X_PREFIX, i);
// 处理横轴字段

View File

@ -44,13 +44,28 @@ public class Order2SQLObj {
private static SQLObj buildSortField(DeSortField f, SQLObj tableObj, int i, List<DatasetTableFieldDTO> originFields, boolean isCross, Map<Long, DatasourceSchemaDTO> dsMap, List<CalParam> fieldParam, List<CalParam> chartParam, PluginManageApi pluginManage) {
Map<String, String> paramMap = Utils.mergeParam(fieldParam, chartParam);
String originField;
String dsType = null;
if (dsMap != null && dsMap.entrySet().iterator().hasNext()) {
Map.Entry<Long, DatasourceSchemaDTO> next = dsMap.entrySet().iterator().next();
dsType = next.getValue().getType();
}
if (ObjectUtils.isNotEmpty(f.getExtField()) && Objects.equals(f.getExtField(), ExtFieldConstant.EXT_CALC)) {
// 解析origin name中有关联的字段生成sql表达式
originField = Utils.calcFieldRegex(f.getOriginName(), tableObj, originFields, isCross, dsMap, paramMap, pluginManage);
} else if (ObjectUtils.isNotEmpty(f.getExtField()) && Objects.equals(f.getExtField(), ExtFieldConstant.EXT_COPY)) {
originField = String.format(SQLConstants.FIELD_NAME, tableObj.getTableAlias(), f.getDataeaseName());
if (StringUtils.equalsIgnoreCase(dsType, "es")) {
originField = String.format(SQLConstants.FIELD_NAME, tableObj.getTableAlias(), f.getOriginName());
} else {
originField = String.format(SQLConstants.FIELD_NAME, tableObj.getTableAlias(), f.getDataeaseName());
}
} else {
originField = String.format(SQLConstants.FIELD_NAME, tableObj.getTableAlias(), f.getDataeaseName());
if (StringUtils.equalsIgnoreCase(dsType, "es")) {
originField = String.format(SQLConstants.FIELD_NAME, tableObj.getTableAlias(), f.getOriginName());
} else {
originField = String.format(SQLConstants.FIELD_NAME, tableObj.getTableAlias(), f.getDataeaseName());
}
}
String fieldAlias = String.format(SQLConstants.FIELD_ALIAS_X_PREFIX, i);
String fieldName = "";

View File

@ -33,6 +33,13 @@ public class Quota2SQLObj {
List<String> yWheres = new ArrayList<>();
List<SQLObj> yOrders = new ArrayList<>();
Map<String, String> fieldsDialect = new HashMap<>();
String dsType = null;
if (dsMap != null && dsMap.entrySet().iterator().hasNext()) {
Map.Entry<Long, DatasourceSchemaDTO> next = dsMap.entrySet().iterator().next();
dsType = next.getValue().getType();
}
if (!CollectionUtils.isEmpty(fields)) {
for (int i = 0; i < fields.size(); i++) {
ChartViewFieldDTO y = fields.get(i);
@ -47,9 +54,17 @@ public class Quota2SQLObj {
originField = calcFieldExp;
}
} else if (ObjectUtils.isNotEmpty(y.getExtField()) && Objects.equals(y.getExtField(), ExtFieldConstant.EXT_COPY)) {
originField = String.format(SQLConstants.FIELD_NAME, tableObj.getTableAlias(), y.getDataeaseName());
if (StringUtils.equalsIgnoreCase(dsType, "es")) {
originField = String.format(SQLConstants.FIELD_NAME, tableObj.getTableAlias(), y.getOriginName());
} else {
originField = String.format(SQLConstants.FIELD_NAME, tableObj.getTableAlias(), y.getDataeaseName());
}
} else {
originField = String.format(SQLConstants.FIELD_NAME, tableObj.getTableAlias(), y.getDataeaseName());
if (StringUtils.equalsIgnoreCase(dsType, "es")) {
originField = String.format(SQLConstants.FIELD_NAME, tableObj.getTableAlias(), y.getOriginName());
} else {
originField = String.format(SQLConstants.FIELD_NAME, tableObj.getTableAlias(), y.getDataeaseName());
}
}
String fieldAlias = String.format(SQLConstants.FIELD_ALIAS_Y_PREFIX, i);
// 处理纵轴字段
@ -100,7 +115,7 @@ public class Quota2SQLObj {
String cast = String.format(SQLConstants.CAST, originField, Objects.equals(y.getDeType(), DeTypeConstants.DE_INT) ? SQLConstants.DEFAULT_INT_FORMAT : SQLConstants.DEFAULT_FLOAT_FORMAT);
if (StringUtils.equalsIgnoreCase(y.getSummary(), "count_distinct")) {
fieldName = String.format(SQLConstants.AGG_FIELD, "COUNT", "DISTINCT " + cast);
} else if (y.getSummary() == null){
} else if (y.getSummary() == null) {
// 透视表自定义汇总不用聚合
fieldName = cast;
} else {

View File

@ -18,6 +18,7 @@ import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import java.util.*;
import java.util.stream.Collectors;
/**
* @Author Junjun
@ -96,6 +97,13 @@ public class WhereTree2Str {
Map<String, String> paramMap = Utils.mergeParam(fieldParam, chartParam);
String whereName = "";
String originName;
String dsType = null;
if (dsMap != null && dsMap.entrySet().iterator().hasNext()) {
Map.Entry<Long, DatasourceSchemaDTO> next = dsMap.entrySet().iterator().next();
dsType = next.getValue().getType();
}
if (ObjectUtils.isNotEmpty(field.getExtField()) && Objects.equals(field.getExtField(), ExtFieldConstant.EXT_CALC)) {
// 解析origin name中有关联的字段生成sql表达式
String calcFieldExp = Utils.calcFieldRegex(field.getOriginName(), tableObj, originFields, isCross, dsMap, paramMap, pluginManage);
@ -106,9 +114,17 @@ public class WhereTree2Str {
originName = calcFieldExp;
}
} else if (ObjectUtils.isNotEmpty(field.getExtField()) && Objects.equals(field.getExtField(), ExtFieldConstant.EXT_COPY)) {
originName = String.format(SQLConstants.FIELD_NAME, tableObj.getTableAlias(), field.getDataeaseName());
if (StringUtils.equalsIgnoreCase(dsType, "es")) {
originName = String.format(SQLConstants.FIELD_NAME, tableObj.getTableAlias(), field.getOriginName());
} else {
originName = String.format(SQLConstants.FIELD_NAME, tableObj.getTableAlias(), field.getDataeaseName());
}
} else {
originName = String.format(SQLConstants.FIELD_NAME, tableObj.getTableAlias(), field.getDataeaseName());
if (StringUtils.equalsIgnoreCase(dsType, "es")) {
originName = String.format(SQLConstants.FIELD_NAME, tableObj.getTableAlias(), field.getOriginName());
} else {
originName = String.format(SQLConstants.FIELD_NAME, tableObj.getTableAlias(), field.getDataeaseName());
}
}
if (field.getDeType() == 1) {
if (field.getDeExtractType() == 0 || field.getDeExtractType() == 5) {
@ -127,7 +143,14 @@ public class WhereTree2Str {
originName = String.format(SQLConstants.DE_STR_TO_DATE, String.format(SQLConstants.CONCAT, "'1970-01-01 '", originName), SQLConstants.DEFAULT_DATE_FORMAT);
}
}
whereName = originName;
if (StringUtils.equalsIgnoreCase(field.getType(), "date")
|| (StringUtils.equalsIgnoreCase(dsMap.entrySet().iterator().next().getValue().getType(), "oracle") && StringUtils.equalsIgnoreCase(field.getType(), "timestamp"))) {
whereName = String.format(SQLConstants.DE_CAST_DATE_FORMAT, originName,
SQLConstants.DEFAULT_DATE_FORMAT,
SQLConstants.DEFAULT_DATE_FORMAT);
} else {
whereName = originName;
}
}
} else if (field.getDeType() == 2 || field.getDeType() == 3) {
if (field.getDeExtractType() == 0 || field.getDeExtractType() == 5) {
@ -148,7 +171,12 @@ public class WhereTree2Str {
if (StringUtils.equalsIgnoreCase(item.getFilterType(), "enum")) {
if (CollectionUtils.isNotEmpty(item.getEnumValue())) {
res = "(" + whereName + " IN ('" + String.join("','", item.getEnumValue()) + "'))";
if (StringUtils.containsIgnoreCase(field.getType(), "NVARCHAR")
|| StringUtils.containsIgnoreCase(field.getType(), "NCHAR")) {
res = "(" + whereName + " IN (" + item.getEnumValue().stream().map(str -> "'" + SQLConstants.MSSQL_N_PREFIX + str + "'").collect(Collectors.joining(",")) + "))";
} else {
res = "(" + whereName + " IN ('" + String.join("','", item.getEnumValue()) + "'))";
}
}
} else {
String value = item.getValue();
@ -168,9 +196,19 @@ public class WhereTree2Str {
} 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(",")) + "')";
if (StringUtils.containsIgnoreCase(field.getType(), "NVARCHAR")
|| StringUtils.containsIgnoreCase(field.getType(), "NCHAR")) {
whereValue = "(" + Arrays.stream(value.split(",")).map(str -> "'" + SQLConstants.MSSQL_N_PREFIX + str + "'").collect(Collectors.joining(",")) + ")";
} else {
whereValue = "('" + String.join("','", value.split(",")) + "')";
}
} else if (StringUtils.containsIgnoreCase(item.getTerm(), "like")) {
whereValue = "'%" + value + "%'";
if (StringUtils.containsIgnoreCase(field.getType(), "NVARCHAR")
|| StringUtils.containsIgnoreCase(field.getType(), "NCHAR")) {
whereValue = "'" + SQLConstants.MSSQL_N_PREFIX + "%" + value + "%'";
} else {
whereValue = "'%" + value + "%'";
}
} else {
// 如果是时间字段过滤当条件是等于和不等于的时候转换成between和not between
if (field.getDeType() == 1) {
@ -209,7 +247,12 @@ public class WhereTree2Str {
whereValue = String.format(SQLConstants.WHERE_VALUE_VALUE, value);
}
} else {
whereValue = String.format(SQLConstants.WHERE_VALUE_VALUE, value);
if (StringUtils.containsIgnoreCase(field.getType(), "NVARCHAR")
|| StringUtils.containsIgnoreCase(field.getType(), "NCHAR")) {
whereValue = String.format(SQLConstants.WHERE_VALUE_VALUE_CH, value);
} else {
whereValue = String.format(SQLConstants.WHERE_VALUE_VALUE, value);
}
}
}
SQLObj build = SQLObj.builder().whereField(whereName).whereTermAndValue(whereTerm + whereValue).build();

View File

@ -42,6 +42,7 @@ import io.dataease.extensions.view.dto.DatasetRowPermissionsTreeObj;
import io.dataease.i18n.Translator;
import io.dataease.license.config.XpackInteract;
import io.dataease.license.manage.F2CLicLimitedManage;
import io.dataease.license.utils.LicenseUtil;
import io.dataease.model.ExportTaskDTO;
import io.dataease.system.manage.CoreUserManage;
import io.dataease.system.manage.SysParameterManage;
@ -65,6 +66,8 @@ import org.springframework.transaction.annotation.Transactional;
import java.io.*;
import java.net.InetAddress;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.text.DecimalFormat;
import java.util.*;
import java.util.concurrent.Future;
@ -97,7 +100,7 @@ public class ExportCenterManage implements BaseExportApi {
private int max;
@Value("${dataease.export.dataset.limit:100000}")
private int limit;
private Long limit;
private final static String DATA_URL_TITLE = "data:image/jpeg;base64,";
private static final String exportData_path = "/opt/dataease2.0/data/exportData/";
@Value("${dataease.export.page.size:50000}")
@ -169,8 +172,14 @@ public class ExportCenterManage implements BaseExportApi {
CoreExportTask exportTask = exportTaskMapper.selectById(id);
OutputStream outputStream = response.getOutputStream();
response.setContentType("application/vnd.ms-excel");
response.setHeader("Content-disposition", "attachment;filename=" + exportTask.getFileName());
InputStream fileInputStream = new FileInputStream(exportData_path + id + "/" + exportTask.getFileName());
response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(exportTask.getFileName(), StandardCharsets.UTF_8));
InputStream fileInputStream;
if (exportTask.getExportTime() < 1730277243491L) {
fileInputStream = new FileInputStream(exportData_path + id + "/" + exportTask.getFileName());
} else {
fileInputStream = new FileInputStream(exportData_path + id + "/" + id + ".xlsx");
}
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = fileInputStream.read(buffer)) != -1) {
@ -392,7 +401,7 @@ public class ExportCenterManage implements BaseExportApi {
exportTask.setExportStatus("IN_PROGRESS");
exportTaskMapper.updateById(exportTask);
getDataFillingApi().writeExcel(dataPath + "/" + exportTask.getFileName(),
getDataFillingApi().writeExcel(dataPath + "/" + exportTask.getId() + ".xlsx",
new DataFillFormTableDataRequest()
.setId(Long.parseLong(exportTask.getExportFrom()))
.setWithoutLogs(true)
@ -402,7 +411,7 @@ public class ExportCenterManage implements BaseExportApi {
exportTask.setExportProgress("100");
exportTask.setExportStatus("SUCCESS");
setFileSize(dataPath + "/" + exportTask.getFileName(), exportTask);
setFileSize(dataPath + "/" + exportTask.getId() + ".xlsx", exportTask);
} catch (Exception e) {
exportTask.setMsg(e.getMessage());
LogUtil.error("Failed to export data", e);
@ -422,6 +431,7 @@ public class ExportCenterManage implements BaseExportApi {
TokenUserBO tokenUserBO = AuthUtils.getUser();
Future future = scheduledThreadPoolExecutor.submit(() -> {
LicenseUtil.validate();
AuthUtils.setUser(tokenUserBO);
try {
exportTask.setExportStatus("IN_PROGRESS");
@ -496,97 +506,105 @@ public class ExportCenterManage implements BaseExportApi {
Field2SQLObj.field2sqlObj(sqlMeta, allFields, allFields, crossDs, dsMap, Utils.getParams(allFields), null, pluginManage);
WhereTree2Str.transFilterTrees(sqlMeta, rowPermissionsTree, allFields, crossDs, dsMap, Utils.getParams(allFields), null, pluginManage);
Order2SQLObj.getOrders(sqlMeta, dto.getSortFields(), allFields, crossDs, dsMap, Utils.getParams(allFields), null, pluginManage);
String replaceSql = provider.rebuildSQL(SQLProvider.createQuerySQL(sqlMeta, false, false, false), sqlMeta, crossDs, dsMap);
Long totalCount = datasetDataManage.getDatasetTotal(dto, replaceSql, null);
Long curLimit = getExportLimit();
totalCount = totalCount > curLimit ? curLimit : totalCount;
Long totalPage = (totalCount / extractPageSize) + (totalCount % extractPageSize > 0 ? 1 : 0);
Long sheetLimit = 1000000L;
Long sheetCount = (totalCount / sheetLimit) + (totalCount % sheetLimit > 0 ? 1 : 0);
Workbook wb = new SXSSFWorkbook();
FileOutputStream fileOutputStream = new FileOutputStream(dataPath + "/" + request.getFilename() + ".xlsx");
Sheet detailsSheet = wb.createSheet("数据");
List<List<String>> details = new ArrayList<>();
for (Integer p = 0; p < totalPage; p++) {
String querySQL = SQLProvider.createQuerySQLWithLimit(sqlMeta, false, needOrder, false, p * extractPageSize + extractPageSize, extractPageSize);
if (totalPage == 1) {
querySQL = SQLProvider.createQuerySQLWithLimit(sqlMeta, false, needOrder, false, 0, totalCount.intValue());
FileOutputStream fileOutputStream = new FileOutputStream(dataPath + "/" + exportTask.getId() + ".xlsx");
for (Long s = 1L; s < sheetCount + 1; s++) {
Long sheetSize;
if (s.equals(sheetCount)) {
sheetSize = totalCount - (s - 1) * sheetLimit;
} else {
sheetSize = sheetLimit;
}
querySQL = provider.rebuildSQL(querySQL, sqlMeta, crossDs, dsMap);
DatasourceRequest datasourceRequest = new DatasourceRequest();
datasourceRequest.setQuery(querySQL);
datasourceRequest.setDsList(dsMap);
Map<String, Object> previewData = datasetDataManage.buildPreviewData(provider.fetchResultField(datasourceRequest), allFields, desensitizationList);
List<Map<String, Object>> data = (List<Map<String, Object>>) previewData.get("data");
if (p == 0L) {
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);
List<String> header = new ArrayList<>();
for (DatasetTableFieldDTO field : allFields) {
header.add(field.getName());
Long pageSize = (sheetSize / extractPageSize) + (sheetSize % extractPageSize > 0 ? 1 : 0);
Sheet detailsSheet = null;
List<List<String>> details = new ArrayList<>();
for (Long p = 0L; p < pageSize; p++) {
String querySQL = SQLProvider.createQuerySQLWithLimit(sqlMeta, false, needOrder, false, p.intValue() * extractPageSize, extractPageSize);
if (pageSize == 1) {
querySQL = SQLProvider.createQuerySQLWithLimit(sqlMeta, false, needOrder, false, 0, sheetSize.intValue());
}
details.add(header);
for (Map<String, Object> obj : data) {
List<String> row = new ArrayList<>();
querySQL = provider.rebuildSQL(querySQL, sqlMeta, crossDs, dsMap);
DatasourceRequest datasourceRequest = new DatasourceRequest();
datasourceRequest.setQuery(querySQL);
datasourceRequest.setDsList(dsMap);
Map<String, Object> previewData = datasetDataManage.buildPreviewData(provider.fetchResultField(datasourceRequest), allFields, desensitizationList);
List<Map<String, Object>> data = (List<Map<String, Object>>) previewData.get("data");
if (p.equals(0L)) {
detailsSheet = wb.createSheet("数据-" + s);
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);
List<String> header = new ArrayList<>();
for (DatasetTableFieldDTO field : allFields) {
String string = (String) obj.get(field.getDataeaseName());
row.add(string);
header.add(field.getName());
}
details.add(row);
}
if (CollectionUtils.isNotEmpty(details)) {
for (int i = 0; i < details.size(); i++) {
Row row = detailsSheet.createRow(i);
List<String> rowData = details.get(i);
if (rowData != null) {
for (int j = 0; j < rowData.size(); j++) {
Cell cell = row.createCell(j);
if (i == 0) {
cell.setCellValue(rowData.get(j));
cell.setCellStyle(cellStyle);
detailsSheet.setColumnWidth(j, 255 * 20);
} else {
cell.setCellValue(rowData.get(j));
details.add(header);
for (Map<String, Object> obj : data) {
List<String> row = new ArrayList<>();
for (DatasetTableFieldDTO field : allFields) {
String string = (String) obj.get(field.getDataeaseName());
row.add(string);
}
details.add(row);
}
if (CollectionUtils.isNotEmpty(details)) {
for (int i = 0; i < details.size(); i++) {
Row row = detailsSheet.createRow(i);
List<String> rowData = details.get(i);
if (rowData != null) {
for (int j = 0; j < rowData.size(); j++) {
Cell cell = row.createCell(j);
if (i == 0) {
cell.setCellValue(rowData.get(j));
cell.setCellStyle(cellStyle);
detailsSheet.setColumnWidth(j, 255 * 20);
} else {
cell.setCellValue(rowData.get(j));
}
}
}
}
}
}
} else {
details.clear();
for (Map<String, Object> obj : data) {
List<String> row = new ArrayList<>();
for (DatasetTableFieldDTO field : allFields) {
String string = (String) obj.get(field.getDataeaseName());
row.add(string);
} else {
details.clear();
for (Map<String, Object> obj : data) {
List<String> row = new ArrayList<>();
for (DatasetTableFieldDTO field : allFields) {
String string = (String) obj.get(field.getDataeaseName());
row.add(string);
}
details.add(row);
}
details.add(row);
}
int lastNum = detailsSheet.getLastRowNum();
for (int i = 0; i < details.size(); i++) {
Row row = detailsSheet.createRow(i + lastNum + 1);
List<String> rowData = details.get(i);
if (rowData != null) {
for (int j = 0; j < rowData.size(); j++) {
Cell cell = row.createCell(j);
cell.setCellValue(rowData.get(j));
int lastNum = detailsSheet.getLastRowNum();
for (int i = 0; i < details.size(); i++) {
Row row = detailsSheet.createRow(i + lastNum + 1);
List<String> rowData = details.get(i);
if (rowData != null) {
for (int j = 0; j < rowData.size(); j++) {
Cell cell = row.createCell(j);
cell.setCellValue(rowData.get(j));
}
}
}
}
exportTask.setExportStatus("IN_PROGRESS");
double exportRogress2 = (double) ((double) s - 1) / ((double) sheetCount);
double exportRogress = (double) ((double) (p + 1) / (double) pageSize) * ((double) 1 / sheetCount);
DecimalFormat df = new DecimalFormat("#.##");
String formattedResult = df.format((exportRogress + exportRogress2) * 100);
exportTask.setExportProgress(formattedResult);
exportTaskMapper.updateById(exportTask);
}
exportTask.setExportStatus("IN_PROGRESS");
double exportRogress = (double) ((double) p / (double) totalPage);
DecimalFormat df = new DecimalFormat("#.##");
String formattedResult = df.format(exportRogress * 100);
exportTask.setExportProgress(formattedResult);
exportTaskMapper.updateById(exportTask);
}
wb.write(fileOutputStream);
fileOutputStream.flush();
@ -594,7 +612,7 @@ public class ExportCenterManage implements BaseExportApi {
wb.close();
exportTask.setExportProgress("100");
exportTask.setExportStatus("SUCCESS");
setFileSize(dataPath + "/" + request.getFilename() + ".xlsx", exportTask);
setFileSize(dataPath + "/" + exportTask.getId() + ".xlsx", exportTask);
} catch (Exception e) {
LogUtil.error("Failed to export data", e);
@ -613,6 +631,7 @@ public class ExportCenterManage implements BaseExportApi {
boolean isCreated = directory.mkdir();
TokenUserBO tokenUserBO = AuthUtils.getUser();
Future future = scheduledThreadPoolExecutor.submit(() -> {
LicenseUtil.validate();
AuthUtils.setUser(tokenUserBO);
try {
exportTask.setExportStatus("IN_PROGRESS");
@ -663,14 +682,14 @@ public class ExportCenterManage implements BaseExportApi {
ChartDataServer.setExcelData(detailsSheet, cellStyle, header, details, detailFields, excelTypes);
}
}
try (FileOutputStream outputStream = new FileOutputStream(dataPath + "/" + request.getViewName() + ".xlsx")) {
try (FileOutputStream outputStream = new FileOutputStream(dataPath + "/" + exportTask.getId() + ".xlsx")) {
wb.write(outputStream);
outputStream.flush();
}
wb.close();
exportTask.setExportProgress("100");
exportTask.setExportStatus("SUCCESS");
setFileSize(dataPath + "/" + request.getViewName() + ".xlsx", exportTask);
setFileSize(dataPath + "/" + exportTask.getId() + ".xlsx", exportTask);
} catch (Exception e) {
exportTask.setMsg(e.getMessage());
LogUtil.error("Failed to export data", e);

View File

@ -1,9 +1,9 @@
package io.dataease.home;
import io.dataease.license.utils.LicenseUtil;
import io.dataease.home.manage.DeIndexManage;
import io.dataease.utils.ModelUtils;
import io.dataease.utils.RsaUtils;
import org.springframework.beans.factory.annotation.Value;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@ -13,8 +13,9 @@ import org.springframework.web.bind.annotation.RestController;
@RequestMapping
public class RestIndexController {
@Value("${dataease.xpack-front-distributed:false}")
private boolean xpackFrontDistributed;
@Resource
private DeIndexManage deIndexManage;
@GetMapping("/dekey")
@ResponseBody
@ -31,8 +32,8 @@ public class RestIndexController {
@GetMapping("/xpackModel")
@ResponseBody
public boolean xpackModel() {
return xpackFrontDistributed && LicenseUtil.licenseValid();
public Boolean xpackModel() {
return deIndexManage.xpackModel();
}
}

View File

@ -0,0 +1,13 @@
package io.dataease.home.manage;
import io.dataease.license.config.XpackInteract;
import org.springframework.stereotype.Component;
@Component
public class DeIndexManage {
@XpackInteract(value = "deIndexManage", replace = true)
public Boolean xpackModel() {
return null;
}
}

View File

@ -18,9 +18,9 @@ public class DeDataFillingTaskExecutor {
protected static final String IS_TEMP_TASK = "isTempTask";
protected static final String IS_RETRY_TASK = "isRetryTask";
private static final String JOB_GROUP = "REPORT_TASK";
private static final String RETRY_JOB_GROUP = "RETRY_REPORT_TASK";
private static final String TEMP_JOB_GROUP = "TEMP_REPORT_TASK";
private static final String JOB_GROUP = "DATA_FILLING_TASK";
private static final String RETRY_JOB_GROUP = "RETRY_DATA_FILLING_TASK";
private static final String TEMP_JOB_GROUP = "TEMP_DATA_FILLING_TASK";
@Resource
private ScheduleManager scheduleManager;

View File

@ -2,6 +2,7 @@ package io.dataease.job.schedule;
import io.dataease.license.utils.LicenseUtil;
import io.dataease.utils.CommonBeanFactory;
import io.dataease.utils.LogUtil;
import org.quartz.*;
import org.springframework.stereotype.Component;
@ -18,10 +19,14 @@ public class DeXpackDataFillingScheduleJob implements Job {
JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();
DeDataFillingTaskExecutor deTaskExecutor = CommonBeanFactory.getBean(DeDataFillingTaskExecutor.class);
assert deTaskExecutor != null;
LicenseUtil.validate();
boolean taskLoaded = deTaskExecutor.execute(jobDataMap);
if (!taskLoaded) {
Objects.requireNonNull(CommonBeanFactory.getBean(ScheduleManager.class)).removeJob(jobKey, trigger.getKey());
try {
LicenseUtil.validate();
boolean taskLoaded = deTaskExecutor.execute(jobDataMap);
if (!taskLoaded) {
Objects.requireNonNull(CommonBeanFactory.getBean(ScheduleManager.class)).removeJob(jobKey, trigger.getKey());
}
} catch (Exception e) {
LogUtil.error(e.getMessage(), e.getCause());
}
}
}

View File

@ -18,7 +18,7 @@ public interface ResourceMonitorMapper {
@Select("select count(id) from core_dataset_group")
int datasetCount();
@Select("select count(id) from data_visualization_info where delete_flag = 0")
@Select("select count(id) from data_visualization_info where delete_flag = 0 and pid != -1")
int vCount();
@Select("select id, name, pid, type, status from core_datasource")
@ -27,7 +27,7 @@ public interface ResourceMonitorMapper {
@Select("select id, name, pid, node_type from core_dataset_group")
List<DatasetFreeResource> queryFreeDataset();
@Select("select id, name, pid, node_type, type from data_visualization_info where delete_flag = 0")
@Select("select id, name, pid, node_type, type from data_visualization_info where delete_flag = 0 and pid != -1")
List<VisualFreeResource> queryFreeVusial();
@Delete("delete from core_datasource")

View File

@ -0,0 +1,110 @@
package io.dataease.share.interceptor;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.interfaces.Verification;
import io.dataease.auth.DeLinkPermit;
import io.dataease.constant.AuthConstant;
import io.dataease.exception.DEException;
import io.dataease.share.manage.XpackShareManage;
import io.dataease.share.util.LinkTokenUtil;
import io.dataease.utils.LogUtil;
import io.dataease.utils.ServletUtils;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.Objects;
@Aspect
@Component
public class DeLinkAop {
private static final String PARAM_VARIABLE_PREFIX = "p";
private static final String SPRING_EL_FLAG = "#";
private final ExpressionParser parser = new SpelExpressionParser();
@Resource
private XpackShareManage xpackShareManage;
@Around(value = "@annotation(io.dataease.auth.DeLinkPermit)")
public Object logAround(ProceedingJoinPoint point) throws Throwable {
Object[] params = point.getArgs();
String linkToken = ServletUtils.getHead(AuthConstant.LINK_TOKEN_KEY);
if (StringUtils.isNotBlank(linkToken)) {
MethodSignature ms = (MethodSignature) point.getSignature();
Method method = ms.getMethod();
DeLinkPermit deLinkPermit = method.getAnnotation(DeLinkPermit.class);
String value = deLinkPermit.value();
if (StringUtils.isBlank(value)) {
value = SPRING_EL_FLAG + PARAM_VARIABLE_PREFIX + "0";
}
Long id = getExpression(params, value);
DecodedJWT jwt = JWT.decode(linkToken);
Long resourceId = jwt.getClaim("resourceId").asLong();
if (!id.equals(resourceId)) {
DEException.throwException("link token invalid");
return false;
}
Long uid = jwt.getClaim("uid").asLong();
String secret = xpackShareManage.queryPwd(resourceId, uid);
if (StringUtils.isBlank(secret)) {
secret = LinkTokenUtil.defaultPwd;
}
Algorithm algorithm = Algorithm.HMAC256(secret);
Verification verification = JWT.require(algorithm);
JWTVerifier verifier = verification.build();
DecodedJWT decode = JWT.decode(linkToken);
algorithm.verify(decode);
verifier.verify(linkToken);
}
try {
return point.proceed(params);
} catch (Exception e) {
LogUtil.error(e.getMessage());
throw e;
}
}
public Long getExpression(Object[] params, String expression) {
StandardEvaluationContext context = buildContext(params);
Object o = resolveValue(expression, context);
if (ObjectUtils.isNotEmpty(o)) return Long.parseLong(o.toString());
return null;
}
private StandardEvaluationContext buildContext(Object[] params) {
StandardEvaluationContext context = new StandardEvaluationContext();
if (params != null && params.length == 1) {
context.setRootObject(params[0]);
}
for (int i = 0; i < Objects.requireNonNull(params).length; i++) {
Object paramValue = params[i];
context.setVariable(PARAM_VARIABLE_PREFIX + i, paramValue);
}
return context;
}
private Object resolveValue(String exp, EvaluationContext context) {
if (StringUtils.contains(exp, SPRING_EL_FLAG)) {
Expression expression = parser.parseExpression(exp);
return expression.getValue(context);
}
return exp;
}
}

View File

@ -0,0 +1,54 @@
package io.dataease.share.interceptor;
import io.dataease.auth.DeLinkPermit;
import io.dataease.constant.AuthConstant;
import io.dataease.exception.DEException;
import io.dataease.utils.ServletUtils;
import io.dataease.utils.WhitelistUtils;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import java.util.Arrays;
import java.util.List;
@Component
public class LinkInterceptor implements HandlerInterceptor {
private final static String whiteListText = "/user/ipInfo, /apisix/check";
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String linkToken = ServletUtils.getHead(AuthConstant.LINK_TOKEN_KEY);
if (linkToken == null) {
return true;
}
if (handler instanceof HandlerMethod handlerMethod) {
DeLinkPermit deLinkPermit = handlerMethod.getMethodAnnotation(DeLinkPermit.class);
if (deLinkPermit == null) {
List<String> whiteList = Arrays.stream(StringUtils.split(whiteListText, ",")).map(String::trim).toList();
String requestURI = ServletUtils.request().getRequestURI();
if (StringUtils.startsWith(requestURI, WhitelistUtils.getContextPath())) {
requestURI = requestURI.replaceFirst(WhitelistUtils.getContextPath(), "");
}
if (StringUtils.startsWith(requestURI, AuthConstant.DE_API_PREFIX)) {
requestURI = requestURI.replaceFirst(AuthConstant.DE_API_PREFIX, "");
}
boolean valid = whiteList.contains(requestURI);
if (!valid) {
DEException.throwException("分享链接Token不支持访问当前url[" + requestURI + "]");
}
return true;
}
}
return true;
}
}

View File

@ -3,6 +3,7 @@ package io.dataease.share.manage;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.dataease.api.system.vo.ShareBaseVO;
import io.dataease.api.visualization.request.VisualizationWorkbranchQueryRequest;
import io.dataease.api.xpack.share.request.XpackShareProxyRequest;
import io.dataease.api.xpack.share.request.XpackSharePwdValidator;
@ -21,6 +22,7 @@ import io.dataease.share.dao.auto.mapper.XpackShareMapper;
import io.dataease.share.dao.ext.mapper.XpackShareExtMapper;
import io.dataease.share.dao.ext.po.XpackSharePO;
import io.dataease.share.util.LinkTokenUtil;
import io.dataease.system.manage.SysParameterManage;
import io.dataease.utils.*;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
@ -51,6 +53,9 @@ public class XpackShareManage {
@Resource
private ShareTicketManage shareTicketManage;
@Resource
private SysParameterManage sysParameterManage;
public XpackShare queryByResource(Long resourceId) {
Long userId = AuthUtils.getUser().getUserId();
QueryWrapper<XpackShare> queryWrapper = new QueryWrapper<>();
@ -59,6 +64,15 @@ public class XpackShareManage {
return xpackShareMapper.selectOne(queryWrapper);
}
public String queryPwd(Long resourceId, Long userId) {
QueryWrapper<XpackShare> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("creator", userId);
queryWrapper.eq("resource_id", resourceId);
XpackShare xpackShare = xpackShareMapper.selectOne(queryWrapper);
if (ObjectUtils.isEmpty(xpackShare)) return null;
return xpackShare.getPwd();
}
@Transactional
public void switcher(Long resourceId) {
XpackShare originData = queryByResource(resourceId);
@ -190,7 +204,20 @@ public class XpackShareManage {
return CommonBeanFactory.getBean(this.getClass());
}
private boolean peRequireValid(ShareBaseVO sharedBase, XpackShare share) {
if (ObjectUtils.isEmpty(sharedBase) || !sharedBase.isPeRequire()) return true;
Long exp = share.getExp();
String pwd = share.getPwd();
return StringUtils.isNotBlank(pwd) && ObjectUtils.isNotEmpty(exp) && exp > 0L;
}
public XpackShareProxyVO proxyInfo(XpackShareProxyRequest request) {
ShareBaseVO sharedBase = sysParameterManage.shareBase();
if (ObjectUtils.isNotEmpty(sharedBase) && sharedBase.isDisable()) {
XpackShareProxyVO vo = new XpackShareProxyVO();
vo.setShareDisable(true);
return vo;
}
boolean inIframeError = request.isInIframe() && !LicenseUtil.licenseValid();
if (inIframeError) {
return new XpackShareProxyVO();
@ -200,13 +227,18 @@ public class XpackShareManage {
XpackShare xpackShare = xpackShareMapper.selectOne(queryWrapper);
if (ObjectUtils.isEmpty(xpackShare))
return null;
if (!peRequireValid(sharedBase, xpackShare)) {
XpackShareProxyVO vo = new XpackShareProxyVO();
vo.setPeRequireValid(false);
return vo;
}
String linkToken = LinkTokenUtil.generate(xpackShare.getCreator(), xpackShare.getResourceId(), xpackShare.getExp(), xpackShare.getPwd(), xpackShare.getOid());
HttpServletResponse response = ServletUtils.response();
response.addHeader(AuthConstant.LINK_TOKEN_KEY, linkToken);
Integer type = xpackShare.getType();
String typeText = (ObjectUtils.isNotEmpty(type) && type == 1) ? "dashboard" : "dataV";
TicketValidVO validVO = shareTicketManage.validateTicket(request.getTicket(), xpackShare);
return new XpackShareProxyVO(xpackShare.getResourceId(), xpackShare.getCreator(), linkExp(xpackShare), pwdValid(xpackShare, request.getCiphertext()), typeText, inIframeError, validVO);
return new XpackShareProxyVO(xpackShare.getResourceId(), xpackShare.getCreator(), linkExp(xpackShare), pwdValid(xpackShare, request.getCiphertext()), typeText, inIframeError, false, true, validVO);
}
private boolean linkExp(XpackShare xpackShare) {

View File

@ -9,7 +9,7 @@ import org.apache.commons.lang3.StringUtils;
import java.util.Date;
public class LinkTokenUtil {
private static final String defaultPwd = "link-pwd-fit2cloud";
public static final String defaultPwd = "link-pwd-fit2cloud";
public static String generate(Long uid, Long resourceId, Long exp, String pwd, Long oid) {
pwd = StringUtils.isBlank(pwd) ? defaultPwd : pwd;
Algorithm algorithm = Algorithm.HMAC256(pwd);

View File

@ -5,14 +5,17 @@ import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.algorithms.Algorithm;
import io.dataease.api.permissions.login.dto.PwdLoginDTO;
import io.dataease.auth.bo.TokenUserBO;
import io.dataease.auth.config.SubstituleLoginConfig;
import io.dataease.auth.vo.TokenVO;
import io.dataease.exception.DEException;
import io.dataease.i18n.Translator;
import io.dataease.utils.LogUtil;
import io.dataease.utils.Md5Utils;
import io.dataease.utils.RsaUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
@Component
@ConditionalOnMissingBean(name = "loginServer")
@ -21,11 +24,26 @@ import org.springframework.web.bind.annotation.RestController;
public class SubstituleLoginServer {
@PostMapping("/login/localLogin")
public TokenVO localLogin(PwdLoginDTO dto) {
public TokenVO localLogin(@RequestBody PwdLoginDTO dto) {
String name = dto.getName();
name = RsaUtils.decryptStr(name);
String pwd = dto.getPwd();
pwd = RsaUtils.decryptStr(pwd);
dto.setName(name);
dto.setPwd(pwd);
if (!StringUtils.equals("admin", name)) {
DEException.throwException("仅admin账号可用");
}
if (!StringUtils.equals(pwd, SubstituleLoginConfig.getPwd())) {
DEException.throwException(Translator.get("i18n_login_name_pwd_err"));
}
TokenUserBO tokenUserBO = new TokenUserBO();
tokenUserBO.setUserId(1L);
tokenUserBO.setDefaultOid(1L);
String md5Pwd = "83d923c9f1d8fcaa46cae0ed2aaa81b5";
String md5Pwd = Md5Utils.md5(pwd);
return generate(tokenUserBO, md5Pwd);
}

View File

@ -1,7 +1,9 @@
package io.dataease.system.manage;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import io.dataease.api.system.request.OnlineMapEditor;
import io.dataease.api.system.vo.SettingItemVO;
import io.dataease.api.system.vo.ShareBaseVO;
import io.dataease.datasource.server.DatasourceServer;
import io.dataease.license.config.XpackInteract;
import io.dataease.system.dao.auto.entity.CoreSysSetting;
@ -13,6 +15,7 @@ import io.dataease.utils.IDUtils;
import io.dataease.utils.SystemSettingUtils;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
@ -30,7 +33,7 @@ public class SysParameterManage {
@Value("${dataease.demo-tips-content:#{null}}")
private String demoTipsContent;
private static final String mapKey = "map.key";
private static final String MAP_KEY_PREFIX = "map.";
@Resource
private CoreSysSettingMapper coreSysSettingMapper;
@ -50,26 +53,39 @@ public class SysParameterManage {
return null;
}
public String queryOnlineMap() {
return singleVal(mapKey);
public OnlineMapEditor queryOnlineMap() {
var editor = new OnlineMapEditor();
List<String> fields = BeanUtils.getFieldNames(OnlineMapEditor.class);
Map<String, String> mapVal = groupVal(MAP_KEY_PREFIX);
fields.forEach(field -> {
String val = mapVal.get(MAP_KEY_PREFIX + field);
if (StringUtils.isNotBlank(val)) {
BeanUtils.setFieldValueByName(editor, field, val, String.class);
}
});
return editor;
}
public void saveOnlineMap(String val) {
QueryWrapper<CoreSysSetting> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("pkey", mapKey);
CoreSysSetting sysSetting = coreSysSettingMapper.selectOne(queryWrapper);
if (ObjectUtils.isEmpty(sysSetting)) {
sysSetting = new CoreSysSetting();
sysSetting.setId(IDUtils.snowID());
sysSetting.setPkey(mapKey);
public void saveOnlineMap(OnlineMapEditor editor) {
List<String> fieldNames = BeanUtils.getFieldNames(OnlineMapEditor.class);
fieldNames.forEach(field -> {
QueryWrapper<CoreSysSetting> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("pkey", MAP_KEY_PREFIX + field);
CoreSysSetting sysSetting = coreSysSettingMapper.selectOne(queryWrapper);
var val = (String) BeanUtils.getFieldValueByName(field, editor);
if (ObjectUtils.isEmpty(sysSetting)) {
sysSetting = new CoreSysSetting();
sysSetting.setId(IDUtils.snowID());
sysSetting.setPkey(MAP_KEY_PREFIX + field);
sysSetting.setPval(val == null ? "" : val);
sysSetting.setType("text");
sysSetting.setSort(1);
coreSysSettingMapper.insert(sysSetting);
return;
}
sysSetting.setPval(val);
sysSetting.setType("text");
sysSetting.setSort(1);
coreSysSettingMapper.insert(sysSetting);
}
sysSetting.setPval(val);
coreSysSettingMapper.updateById(sysSetting);
coreSysSettingMapper.updateById(sysSetting);
});
}
@ -81,7 +97,7 @@ public class SysParameterManage {
if (!CollectionUtils.isEmpty(sysSettings)) {
return sysSettings.stream().collect(Collectors.toMap(CoreSysSetting::getPkey, CoreSysSetting::getPval));
}
return null;
return new HashMap<>();
}
public List<CoreSysSetting> groupList(String groupKey) {
@ -143,4 +159,17 @@ public class SysParameterManage {
private SysParameterManage proxy() {
return CommonBeanFactory.getBean(SysParameterManage.class);
}
public ShareBaseVO shareBase() {
String disableText = singleVal("basic.shareDisable");
String requireText = singleVal("basic.sharePeRequire");
ShareBaseVO vo = new ShareBaseVO();
if (StringUtils.isNotBlank(disableText) && StringUtils.equals("true", disableText)) {
vo.setDisable(true);
}
if (StringUtils.isNotBlank(requireText) && StringUtils.equals("true", requireText)) {
vo.setPeRequire(true);
}
return vo;
}
}

View File

@ -3,6 +3,7 @@ package io.dataease.system.server;
import io.dataease.api.system.SysParameterApi;
import io.dataease.api.system.request.OnlineMapEditor;
import io.dataease.api.system.vo.SettingItemVO;
import io.dataease.api.system.vo.ShareBaseVO;
import io.dataease.constant.XpackSettingConstants;
import io.dataease.system.dao.auto.entity.CoreSysSetting;
import io.dataease.system.manage.SysParameterManage;
@ -27,13 +28,12 @@ public class SysParameterServer implements SysParameterApi {
@Override
public void saveOnlineMap(OnlineMapEditor editor) {
sysParameterManage.saveOnlineMap(editor.getKey());
sysParameterManage.saveOnlineMap(editor);
}
@Override
public String queryOnlineMap() {
String key = sysParameterManage.queryOnlineMap();
return StringUtils.isNotBlank(key) ? key : "";
public OnlineMapEditor queryOnlineMap() {
return sysParameterManage.queryOnlineMap();
}
@Override
@ -70,4 +70,9 @@ public class SysParameterServer implements SysParameterApi {
public Integer defaultLogin() {
return sysParameterManage.defaultLogin();
}
@Override
public ShareBaseVO shareBase() {
return sysParameterManage.shareBase();
}
}

View File

@ -11,6 +11,7 @@ import io.dataease.api.template.vo.MarketLatestReleaseVO;
import io.dataease.api.template.vo.MarketMetaDataVO;
import io.dataease.constant.CommonConstants;
import io.dataease.exception.DEException;
import io.dataease.i18n.Translator;
import io.dataease.operation.manage.CoreOptRecentManage;
import io.dataease.system.manage.SysParameterManage;
import io.dataease.template.dao.auto.entity.VisualizationTemplateCategoryMap;
@ -166,11 +167,11 @@ public class TemplateCenterManage {
public MarketPreviewBaseResponse searchTemplatePreview() {
try {
MarketBaseResponse baseContentRsp = searchTemplate();
List<MarketMetaDataVO> categories = baseContentRsp.getCategories().stream().filter(category -> !"最近使用".equals(category.getLabel())).collect(Collectors.toList());
List<MarketMetaDataVO> categories = baseContentRsp.getCategories().stream().filter(category -> !Translator.get("i18n_template_recent").equals(category.getLabel())).toList();
List<TemplateMarketDTO> contents = baseContentRsp.getContents();
List<TemplateMarketPreviewInfoDTO> previewContents = new ArrayList<>();
categories.forEach(category -> {
if ("推荐".equals(category.getLabel())) {
if (Translator.get("i18n_template_recommend").equals(category.getLabel())) {
previewContents.add(new TemplateMarketPreviewInfoDTO(category, contents.stream().filter(template -> "Y".equals(template.getSuggest())).collect(Collectors.toList())));
} else {
previewContents.add(new TemplateMarketPreviewInfoDTO(category, contents.stream().filter(template -> checkCategoryMatch(template, category.getLabel())).collect(Collectors.toList())));
@ -235,7 +236,7 @@ public class TemplateCenterManage {
List<MarketMetaDataVO> categoryVO = getCategoriesObject().stream().filter(node -> !"全部".equalsIgnoreCase(node.getLabel())).collect(Collectors.toList());
Map<String, String> categoriesMap = categoryVO.stream()
.collect(Collectors.toMap(MarketMetaDataVO::getValue, MarketMetaDataVO::getLabel));
List<String> activeCategoriesName = new ArrayList<>(Arrays.asList("最近使用", "推荐"));
List<String> activeCategoriesName = new ArrayList<>(Arrays.asList(Translator.get("i18n_template_recent"), Translator.get("i18n_template_recommend")));
contents.stream().forEach(templateMarketDTO -> {
Long recentUseTime = useTime.get(templateMarketDTO.getId());
templateMarketDTO.setRecentUseTime(recentUseTime == null ? 0 : recentUseTime);
@ -264,7 +265,7 @@ public class TemplateCenterManage {
public List<MarketMetaDataVO> getCategoriesObject() {
List<MarketMetaDataVO> result = getCategoriesV2();
result.add(0, new MarketMetaDataVO("recent", "最近使用", CommonConstants.TEMPLATE_SOURCE.PUBLIC));
result.add(0, new MarketMetaDataVO("recent", Translator.get("i18n_template_recent"), CommonConstants.TEMPLATE_SOURCE.PUBLIC));
return result;
}
@ -285,7 +286,7 @@ public class TemplateCenterManage {
String resultStr = marketGet(templateParams.get("template.url") + TEMPLATE_META_DATA_URL, null);
MarketMetaDataBaseResponse metaData = JsonUtil.parseObject(resultStr, MarketMetaDataBaseResponse.class);
allCategories.addAll(metaData.getLabels());
allCategories.add(0, new MarketMetaDataVO("suggest", "推荐", CommonConstants.TEMPLATE_SOURCE.PUBLIC));
allCategories.add(0, new MarketMetaDataVO("suggest", Translator.get("i18n_template_recommend"), CommonConstants.TEMPLATE_SOURCE.PUBLIC));
} catch (Exception e) {
LogUtil.error("模板市场分类获取错误", e);
}

View File

@ -16,6 +16,7 @@ import org.apache.ibatis.annotations.Select;
import java.util.List;
import java.util.Map;
import java.util.Set;
@Mapper
public interface ExtDataVisualizationMapper {
@ -51,5 +52,7 @@ public interface ExtDataVisualizationMapper {
List<VisualizationReportFilterVO> queryReportFilter(@Param("dvId") Long dvId,@Param("taskId") Long taskId);
void deleteDataVBatch(@Param("ids") Set<Long> ids);
void deleteViewsBatch(@Param("ids") Set<Long> ids);
}

View File

@ -0,0 +1,42 @@
package io.dataease.visualization.manage;
import io.dataease.dataset.manage.DatasetGroupManage;
import io.dataease.datasource.manage.DataSourceManage;
import io.dataease.model.BusiNodeRequest;
import io.dataease.model.BusiNodeVO;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Component("coreBusiManage")
public class CoreBusiManage {
@Resource
private CoreVisualizationManage coreVisualizationManage;
@Resource
private DataSourceManage dataSourceManage;
@Resource
private DatasetGroupManage datasetGroupManage;
public Map<String, List<BusiNodeVO>> interactiveTree(Map<String, BusiNodeRequest> requestMap) {
Map<String, List<BusiNodeVO>> result = new HashMap<>();
for (Map.Entry<String, BusiNodeRequest> entry : requestMap.entrySet()) {
BusiNodeRequest busiNodeRequest = entry.getValue();
String key = entry.getKey();
if (StringUtils.equalsIgnoreCase(key, "datasource")) {
result.put(key, dataSourceManage.tree(busiNodeRequest));
} else if (StringUtils.equalsIgnoreCase(key, "dataset")) {
result.put(key, datasetGroupManage.tree(busiNodeRequest));
} else if (StringUtils.equalsAnyIgnoreCase(key, "dashboard", "dataV")) {
result.put(key, coreVisualizationManage.tree(busiNodeRequest));
}
}
return result;
}
}

View File

@ -89,7 +89,11 @@ public class CoreVisualizationManage {
});
}
}
extMapper.batchDel(delIds, System.currentTimeMillis(), AuthUtils.getUser().getUserId());
// 删除可视化资源
extDataVisualizationMapper.deleteDataVBatch(delIds);
// 删除图表信息
extDataVisualizationMapper.deleteViewsBatch(delIds);
coreOptRecentManage.saveOpt(id, OptConstants.OPT_RESOURCE_TYPE.VISUALIZATION, OptConstants.OPT_TYPE.DELETE);
}

View File

@ -11,6 +11,7 @@ import io.dataease.api.visualization.request.DataVisualizationBaseRequest;
import io.dataease.api.visualization.request.VisualizationAppExportRequest;
import io.dataease.api.visualization.request.VisualizationWorkbranchQueryRequest;
import io.dataease.api.visualization.vo.*;
import io.dataease.auth.DeLinkPermit;
import io.dataease.chart.dao.auto.entity.CoreChartView;
import io.dataease.chart.dao.auto.mapper.CoreChartViewMapper;
import io.dataease.chart.manage.ChartDataManage;
@ -51,6 +52,7 @@ import io.dataease.visualization.dao.auto.entity.VisualizationWatermark;
import io.dataease.visualization.dao.auto.mapper.DataVisualizationInfoMapper;
import io.dataease.visualization.dao.auto.mapper.VisualizationWatermarkMapper;
import io.dataease.visualization.dao.ext.mapper.ExtDataVisualizationMapper;
import io.dataease.visualization.manage.CoreBusiManage;
import io.dataease.visualization.manage.CoreVisualizationManage;
import io.dataease.visualization.utils.VisualizationUtils;
import jakarta.annotation.Resource;
@ -128,6 +130,9 @@ public class DataVisualizationServer implements DataVisualizationApi {
@Autowired
private CoreDatasourceMapper coreDatasourceMapper;
@Resource
private CoreBusiManage coreBusiManage;
@Override
public DataVisualizationVO findCopyResource(Long dvId, String busiFlag) {
DataVisualizationVO result = findById(new DataVisualizationBaseRequest(dvId, busiFlag));
@ -138,6 +143,7 @@ public class DataVisualizationServer implements DataVisualizationApi {
}
}
@DeLinkPermit("#p0.id")
@DeLog(id = "#p0.id", ot = LogOT.READ, stExp = "#p0.busiFlag")
@Override
@XpackInteract(value = "dataVisualizationServer", original = true)
@ -296,7 +302,7 @@ public class DataVisualizationServer implements DataVisualizationApi {
coreDatasetTableFieldMapper.insert(dsTableFields);
});
List<String> dsGroupNameSave = new ArrayList<>();
// 持久化数据集
newDsGroupInfo.forEach(dsGroup -> {
dsTableIdMap.forEach((key, value) -> {
@ -321,8 +327,10 @@ public class DataVisualizationServer implements DataVisualizationApi {
}
});
if(dsGroupNameSave.contains(dsGroup.getName())){
dsGroup.setName(dsGroup.getName()+"-"+UUID.randomUUID().toString());
}
dsGroupNameSave.add(dsGroup.getName());
datasetGroupManage.innerSave(dsGroup);
});
@ -484,6 +492,11 @@ public class DataVisualizationServer implements DataVisualizationApi {
return coreVisualizationManage.tree(request);
}
@Override
public Map<String, List<BusiNodeVO>> interactiveTree(Map<String, BusiNodeRequest> requestMap) {
return coreBusiManage.interactiveTree(requestMap);
}
@DeLog(id = "#p0.id", pid = "#p0.pid", ot = LogOT.MODIFY, stExp = "#p0.type")
@Transactional
@Override
@ -743,7 +756,6 @@ public class DataVisualizationServer implements DataVisualizationApi {
wrapper.eq("name", request.getName().trim());
wrapper.eq("node_type", request.getNodeType());
wrapper.eq("type", request.getType());
wrapper.eq("org_id", AuthUtils.getUser().getDefaultOid());
if (visualizationInfoMapper.exists(wrapper)) {
DEException.throwException("当前名称已经存在");
}
@ -772,6 +784,9 @@ public class DataVisualizationServer implements DataVisualizationApi {
List<DataVisualizationInfo> list = new ArrayList<>();
DataVisualizationInfo dataVisualizationInfo = visualizationInfoMapper.selectById(id);
list.add(dataVisualizationInfo);
if (dataVisualizationInfo.getPid().equals(dataVisualizationInfo.getId())) {
return list;
}
getParent(list, dataVisualizationInfo);
Collections.reverse(list);
return list;

View File

@ -7,6 +7,7 @@ import io.dataease.api.visualization.dto.VisualizationLinkJumpInfoDTO;
import io.dataease.api.visualization.request.VisualizationLinkJumpBaseRequest;
import io.dataease.api.visualization.response.VisualizationLinkJumpBaseResponse;
import io.dataease.api.visualization.vo.VisualizationViewTableVO;
import io.dataease.auth.DeLinkPermit;
import io.dataease.chart.dao.auto.entity.CoreChartView;
import io.dataease.chart.dao.auto.mapper.CoreChartViewMapper;
import io.dataease.extensions.datasource.dto.DatasetTableFieldDTO;
@ -67,6 +68,7 @@ public class VisualizationLinkJumpService implements VisualizationLinkJumpApi {
return extVisualizationLinkageMapper.queryTableFieldWithViewId(viewId);
}
@DeLinkPermit
//获取仪表板的跳转信息
@Override
public VisualizationLinkJumpBaseResponse queryVisualizationJumpInfo(Long dvId) {

View File

@ -6,6 +6,7 @@ import io.dataease.api.visualization.dto.LinkageInfoDTO;
import io.dataease.api.visualization.dto.VisualizationLinkageDTO;
import io.dataease.api.visualization.request.VisualizationLinkageRequest;
import io.dataease.api.visualization.vo.VisualizationLinkageFieldVO;
import io.dataease.auth.DeLinkPermit;
import io.dataease.chart.dao.auto.entity.CoreChartView;
import io.dataease.chart.dao.auto.mapper.CoreChartViewMapper;
import io.dataease.utils.BeanUtils;
@ -108,6 +109,7 @@ public class VisualizationLinkageService implements VisualizationLinkageApi {
return new BaseRspModel();
}
@DeLinkPermit
@Override
public Map<String, List<String>> getVisualizationAllLinkageInfo(Long dvId) {
List<LinkageInfoDTO> info = extVisualizationLinkageMapper.getPanelAllLinkageInfo(dvId);

View File

@ -2,13 +2,13 @@ package io.dataease.visualization.server;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.core.type.TypeReference;
import com.ibm.icu.impl.coll.CollationLoader;
import io.dataease.api.dataset.vo.CoreDatasetGroupVO;
import io.dataease.api.dataset.vo.CoreDatasetTableFieldVO;
import io.dataease.api.visualization.VisualizationOuterParamsApi;
import io.dataease.api.visualization.dto.VisualizationOuterParamsDTO;
import io.dataease.api.visualization.dto.VisualizationOuterParamsInfoDTO;
import io.dataease.api.visualization.response.VisualizationOuterParamsBaseResponse;
import io.dataease.auth.DeLinkPermit;
import io.dataease.dataset.dao.auto.entity.CoreDatasetTable;
import io.dataease.dataset.dao.auto.mapper.CoreDatasetTableMapper;
import io.dataease.engine.constant.DeTypeConstants;
@ -29,7 +29,10 @@ import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;
/**
@ -98,6 +101,7 @@ public class VisualizationOuterParamsService implements VisualizationOuterParams
}
@DeLinkPermit
@Override
public VisualizationOuterParamsBaseResponse getOuterParamsInfo(String visualizationId) {
List<VisualizationOuterParamsInfoDTO> result = extOuterParamsMapper.getVisualizationOuterParamsInfo(visualizationId);

View File

@ -5,7 +5,7 @@ spring:
username: root
password: Password123@mysql
messages:
basename: i18n/lic,i18n/core,i18n/permissions,i18n/xpack
basename: i18n/lic,i18n/core,i18n/permissions,i18n/xpack,i18n/sync
flyway:
enabled: true
table: de_standalone_version

View File

@ -47,9 +47,9 @@ quartz:
dataease:
version: '@project.version@'
xpack-front-distributed: true
origin-list: http://192.168.1.9:9080
origin-list: http://127.0.0.1:9080
apisix-api:
domain: http://192.168.1.9:9180
domain: http://127.0.0.1:9180
key: edd1c9f034335f136f87ad84b625c8f1
# springdoc-openapi项目配置

View File

@ -0,0 +1,14 @@
INSERT INTO area (id, level, name, pid) VALUES ('156440315', 'district', '大鹏新区', '156440300');
DELETE ccv
FROM
core_chart_view ccv
INNER JOIN data_visualization_info dvi ON ccv.scene_id = dvi.id
WHERE
dvi.delete_flag =1;
delete from data_visualization_info dvi where dvi.delete_flag =1;
ALTER TABLE `core_chart_view`
ADD COLUMN `custom_attr_mobile` longtext NULL COMMENT '图形属性_移动端',
ADD COLUMN `custom_style_mobile` longtext NULL COMMENT '组件样式_移动端';

View File

@ -1,12 +1,10 @@
ALTER TABLE `visualization_outer_params_info`
ADD COLUMN `required` tinyint(1) DEFAULT 0 COMMENT '是否必填',
ADD COLUMN `required` tinyint(1) DEFAULT 0 COMMENT '是否必填',
ADD COLUMN `default_value` varchar(255) DEFAULT NULL COMMENT '默认值 JSON格式',
ADD COLUMN `enabled_default` tinyint(1) NULL DEFAULT 0 COMMENT '是否启用默认值';
update visualization_outer_params_info
set required =0;
ALTER TABLE `xpack_report_info`
ADD COLUMN `show_watermark` tinyint(1) NOT NULL DEFAULT 0 COMMENT '显示水印' AFTER `rid`;
ALTER TABLE `visualization_link_jump_info`
ADD COLUMN `window_size` varchar(255) NULL DEFAULT 'middle' COMMENT '窗口大小large middle small';

View File

@ -0,0 +1,24 @@
INSERT INTO area (id, level, name, pid)
VALUES ('156440315', 'district', '大鹏新区', '156440300');
DELETE ccv
FROM core_chart_view ccv
INNER JOIN data_visualization_info dvi ON ccv.scene_id = dvi.id
WHERE dvi.delete_flag = 1;
delete
from data_visualization_info dvi
where dvi.delete_flag = 1;
DELETE
FROM area
where pid = '156710100'
OR id = '156710100';
ALTER TABLE `core_chart_view`
ADD COLUMN `custom_attr_mobile` longtext NULL COMMENT '图形属性_移动端' AFTER `custom_attr`,
ADD COLUMN `custom_style_mobile` longtext NULL COMMENT '组件样式_移动端' AFTER `custom_style`;
INSERT INTO `core_sys_setting`(`id`, `pkey`, `pval`, `type`, `sort`)
VALUES (1048232869488627717, 'basic.shareDisable', 'false', 'text', 11);
INSERT INTO `core_sys_setting`(`id`, `pkey`, `pval`, `type`, `sort`)
VALUES (1048232869488627718, 'basic.sharePeRequire', 'false', 'text', 12);

View File

@ -62,3 +62,52 @@ i18n_day=Day
i18n_hour=Hour
i18n_minute=Minute
i18n_second=Second
i18n_no_datasource_permission_to_create_column=No datasource permission, cannot create column
i18n_df_folder_cannot_to_search=Folder cannot for search data
i18n_df_no_primary_key=No primary key
i18n_df_cannot_operate_folder=Cannot Operate Folder
i18n_df_cannot_be_none=[%s] Cannot be null
i18n_df_value_cannot_be_none=[%s] value: %s Cannot be null
i18n_df_value_exists_in_database=[%s] value: %s Exists in database
i18n_df_data=Data
i18n_df_start=Start
i18n_df_end=End
i18n_df_datasource_not_found=datasource not found
i18n_df_datasource_does_not_enable_data_filling=function of dataFilling is not enabled
i18n_df_builtin_datasource=builtin datasource
i18n_df_folder_required=folder required
i18n_df_form_not_exists=form not exists
i18n_df_name_can_not_empty=name can not empty
i18n_df_template=template
i18n_df_task_status_is_null_or_finished=task status is null or finished
i18n_df_task_need_task_id=task need taskID
i18n_df_not_current_task_user=not current task user
i18n_df_miss_parameter=miss parameter
i18n_df_no_running_instance=no running instance
i18n_df_value=value
i18n_df_format_error=parse error
i18n_df_cannot_earlier_than=cannot earlier than
i18n_df_cannot_be_all_null=cannot be all null
i18n_df_value_not_in_range=value not in range
i18n_df_value_value_not_in_range=value: %s not in range
i18n_df_required=required
i18n_df_must_unique=must be unique
i18n_df_excel_parsing_error=Excel parse error
i18n_df_excel_is_empty=Excel is empty
i18n_df_excel_template_column_not_fit=count of template columns are not fit
i18n_df_selection=selection
i18n_df_date_format=date format
i18n_df_integer=integer
i18n_df_decimal=decimal
i18n_df_multiple_value_split=use ';' to split multiple value
i18n_df_email_type=email type
i18n_df_phone_type=phone type
i18n_copilot_cross_ds_error=This feature is not supported for cross-source datasets.
i18n_template_recommend=Recommend
i18n_template_recent=Recently Used

View File

@ -81,3 +81,51 @@ i18n_day=\u5929
i18n_hour=\u5C0F\u65F6
i18n_minute=\u5206\u949F
i18n_second=\u79D2
i18n_no_datasource_permission_to_create_column=\u65E0\u6570\u636E\u6E90\u8BBF\u95EE\u6743\u9650\uFF0C\u65E0\u6CD5\u521B\u5EFA\u8868\u5B57\u6BB5
i18n_df_folder_cannot_to_search=\u6587\u4EF6\u5939\u4E0D\u80FD\u67E5\u8BE2\u6570\u636E
i18n_df_no_primary_key=\u6CA1\u6709\u4E3B\u952E
i18n_df_cannot_operate_folder=\u4E0D\u80FD\u64CD\u4F5C\u6587\u4EF6\u5939
i18n_df_cannot_be_none=[%s] \u4E0D\u80FD\u4E3A\u7A7A
i18n_df_value_cannot_be_none=[%s] \u503C: %s \u4E0D\u80FD\u4E3A\u7A7A
i18n_df_value_exists_in_database=[%s] \u503C: %s \u5728\u6570\u636E\u5E93\u4E2D\u5DF2\u5B58\u5728, \u4E0D\u80FD\u91CD\u590D
i18n_df_data=\u6570\u636E
i18n_df_start=\u5F00\u59CB
i18n_df_end=\u7ED3\u675F
i18n_df_datasource_not_found=\u6CA1\u6709\u627E\u5230\u6570\u636E\u6E90
i18n_df_datasource_does_not_enable_data_filling=\u8BE5\u6570\u636E\u6E90\u6CA1\u6709\u542F\u7528\u6570\u636E\u586B\u62A5\u914D\u7F6E
i18n_df_builtin_datasource=\u5185\u5EFA\u6570\u636E\u5E93
i18n_df_folder_required=\u76EE\u5F55\u5FC5\u9009
i18n_df_form_not_exists=\u8868\u5355\u4E0D\u5B58\u5728
i18n_df_name_can_not_empty=\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A
i18n_df_template=\u6A21\u677F
i18n_df_task_status_is_null_or_finished=\u4EFB\u52A1\u72B6\u6001\u4E3A\u7A7A\u6216\u5DF2\u5B8C\u6210
i18n_df_task_need_task_id=\u9700\u6307\u5B9A\u4EFB\u52A1ID
i18n_df_not_current_task_user=\u4E0D\u662F\u5F53\u524D\u4EFB\u52A1\u7684\u76EE\u6807\u7528\u6237
i18n_df_miss_parameter=\u7F3A\u5931\u53C2\u6570
i18n_df_no_running_instance=\u5F53\u524D\u4EFB\u52A1\u6682\u65F6\u65E0\u8FD0\u884C\u5B9E\u4F8B
i18n_df_value=\u503C
i18n_df_format_error=\u683C\u5F0F\u89E3\u6790\u9519\u8BEF
i18n_df_cannot_earlier_than=\u4E0D\u80FD\u65E9\u4E8E
i18n_df_cannot_be_all_null=\u4E0D\u80FD\u53EA\u6709\u4E00\u4E2A\u4E3A\u7A7A
i18n_df_value_not_in_range=\u503C\u4E0D\u5728\u8303\u56F4\u5185
i18n_df_value_value_not_in_range=\u503C: %s \u4E0D\u5728\u8303\u56F4\u5185
i18n_df_required=\u5FC5\u586B
i18n_df_must_unique=\u4E0D\u5141\u8BB8\u91CD\u590D\u503C
i18n_df_excel_parsing_error=Excel\u89E3\u6790\u9519\u8BEF
i18n_df_excel_is_empty=\u8BE5Excel\u6CA1\u6709\u6570\u636E
i18n_df_excel_template_column_not_fit=\u6A21\u677F\u5B57\u6BB5\u4E2A\u6570\u4E0D\u5339\u914D
i18n_df_selection=\u9009\u9879\u503C\u4E3A
i18n_df_date_format=\u65E5\u671F\u683C\u5F0F
i18n_df_integer=\u6574\u5F62\u6570\u5B57
i18n_df_decimal=\u5C0F\u6570\u6570\u5B57
i18n_df_multiple_value_split=\u591A\u4E2A\u503C\u4F7F\u7528\u5206\u53F7";"\u5206\u5272
i18n_df_email_type=\u90AE\u7BB1\u683C\u5F0F
i18n_df_phone_type=\u624B\u673A\u53F7\u683C\u5F0F
i18n_copilot_cross_ds_error=\u8DE8\u6E90\u6570\u636E\u96C6\u4E0D\u652F\u6301\u8BE5\u529F\u80FD
i18n_template_recommend=\u63A8\u8350
i18n_template_recent=\u6700\u8FD1\u4F7F\u7528

View File

@ -2,23 +2,38 @@ login.validator.name1=\u8CEC\u865F/\u90F5\u7BB1/\u624B\u6A5F\u865F\u4E0D\u80FD\u
login.validator.pwd1=\u5BC6\u78BC\u4E0D\u80FD\u70BA\u7A7A
i18n_menu.home=\u9996\u9801
i18n_menu.workbranch=\u5DE5\u4F5C\u81FA
i18n_menu.workbranch=\u5DE5\u4F5C\u53F0
i18n_menu.visualized=\u53EF\u8996\u5316
i18n_menu.template=\u6A21\u7248
i18n_menu.application=\u61C9\u7528
i18n_menu.system=\u7CFB\u7D71\u7BA1\u7406
i18n_menu.template-market=\u6A21\u677F\u5E02\u5834
i18n_menu.template-setting=\u6A21\u677F\u7BA1\u7406
i18n_menu.view=\u6578\u64DA\u5C55\u793A
i18n_menu.data=\u6578\u64DA\u6E96\u5099
i18n_menu.data=\u6578\u64DA\u51C6\u5099
i18n_menu.panel=\u5100\u8868\u677F
i18n_menu.data-filling-manage=\u6578\u64DA\u586B\u5831
i18n_menu.screen=\u6578\u64DA\u5927\u5C4F
i18n_menu.dataset=\u6578\u64DA\u96C6
i18n_menu.datasource=\u6578\u64DA\u6E90
i18n_menu.user=\u7528\u6236\u7BA1\u7406
i18n_menu.org=\u7D44\u7E54\u7BA1\u7406
i18n_menu.auth=\u6B0A\u9650\u914D\u7F6E
i18n_menu.sysVariable=\u7CFB\u7EDF\u53D8\u91CF
i18n_field_name_repeat=\u5177\u6709\u91CD\u8907\u7684\u6B04\u4F4D\u540D\u7A31\uFF1A
i18n_menu.report=\u5B9A\u6642\u5831\u544A
i18n_menu.sync=\u540C\u6B65\u7BA1\u7406
i18n_menu.association=\u8840\u7DE3\u5206\u6790
i18n_menu.threshold=\u544A\u8B66\u7BA1\u7406
i18n_menu.summary=\u6982\u89BD
i18n_menu.ds=\u6578\u64DA\u9023\u63A5\u7BA1\u7406
i18n_menu.task=\u4EFB\u52D9\u7BA1\u7406
i18n_menu.embedded=\u5D4C\u5165\u5F0F\u7BA1\u7406
i18n_menu.plugin=\u63D2\u4EF6\u7BA1\u7406
i18n_menu.platform=\u5E73\u53F0\u5C0D\u63A5
i18n_menu.appearance=\u5916\u89C0\u914D\u7F6E
i18n_menu.sysVariable=\u7CFB\u7D71\u8B8A\u91CF
i18n_menu.sysTypeface=\u5B57\u9AD4\u7BA1\u7406
i18n_menu.font=\u5B57\u9AD4\u7BA1\u7406
i18n_field_name_repeat=\u6709\u91CD\u5FA9\u5B57\u6BB5\u540D\uFF1A
i18n_pid_not_eq_id=\u79FB\u52D5\u76EE\u6A19\u4E0D\u80FD\u662F\u81EA\u5DF1\u6216\u5B50\u76EE\u9304
i18n_ds_name_exists=\u8A72\u5206\u7D44\u4E0B\u540D\u7A31\u91CD\u5FA9
i18n_table_id_can_not_empty=\u67E5\u8A62\u7BC0\u9EDE\u4E0D\u80FD\u70BA\u7A7A
@ -32,14 +47,14 @@ i18n_union_field_can_not_empty=\u95DC\u806F\u5B57\u6BB5\u4E0D\u80FD\u70BA\u7A7A
i18n_table_duplicate=\u76F8\u540C\u7BC0\u9EDE\u9700\u91CD\u65B0\u62D6\u5165\u624D\u80FD\u7E7C\u7E8C\u65B0\u5EFA\u6578\u64DA\u96C6
i18n_no_column_permission=\u6C92\u6709\u5217\u6B0A\u9650
i18n_fetch_error=SQL\u57F7\u884C\u5931\u6557\uFF0C\u8ACB\u6AA2\u67E5\u8868\u3001\u5B57\u6BB5\u3001\u95DC\u806F\u95DC\u7CFB\u7B49\u4FE1\u606F\u662F\u5426\u6B63\u78BA\u4E26\u91CD\u65B0\u7DE8\u8F2F\u3002
i18n_no_datasource_permission=\u65E0\u6570\u636E\u6E90\u8BBF\u95EE\u6743\u9650
i18n_no_dataset_permission=\u65e0\u6570\u636e\u96c6\u8bbf\u95ee\u6743\u9650
i18n_no_datasource_permission=\u7121\u6578\u64DA\u6E90\u8A2A\u554F\u6B0A\u9650
i18n_no_dataset_permission=\u7121\u6578\u64DA\u96C6\u8A2A\u554F\u6B0A\u9650
i18n_not_full=\u7576\u524D\u6578\u64DA\u6E90\u4E0D\u652F\u6301\u5168\u9023\u63A5
i18n_field_circular_ref=\u5B57\u6BB5\u5B58\u5728\u5FAA\u74B0\u5F15\u7528
i18n_chart_not_handler=\u7121\u6CD5\u8655\u7406\u8A72\u5716\u8868\u985E\u578B
i18n_chart_delete=\u8996\u5716\u4E0D\u5B58\u5728
i18n_chart_delete=\u5716\u8868\u4E0D\u5B58\u5728
i18n_no_ds=\u6578\u64DA\u96C6\u4E0D\u5B58\u5728\u6216\u6C92\u6709\u6B0A\u9650
i18n_datasource_delete=\u6578\u64DA\u6E90\u4E0D\u5B58\u5728
i18n_gauge_field_change=\u6240\u7528\u5B57\u6BB5\u767C\u751F\u8B8A\u66F4\uFF0C\u8ACB\u91CD\u65B0\u7DE8\u8F2F
@ -53,9 +68,12 @@ i18n_invalid_ds=\u6578\u64DA\u6E90\u7121\u6548
i18n_user_disable=\u7528\u6236\u5DF2\u88AB\u7981\u7528\uFF0C\u7121\u6CD5\u767B\u9304
i18n_login_name_pwd_err=\u7528\u6236\u540D\u6216\u5BC6\u78BC\u932F\u8AA4
i18n_error_login_type=\u767B\u9304\u985E\u578B\u932F\u8AA4
i18n_schema_is_empty=schema\u70BA\u7A7A\uFF01
i18n_table_name_repeat=\u540D\u7A31\u91CD\u8907:
i18n_sql_not_empty=sql\u4E0D\u80FD\u70BA\u7A7A
i18n_schema_is_empty=schema \u70BA\u7A7A\uFF01
i18n_table_name_repeat=\u540D\u7A31\u91CD\u5FA9:
i18n_sql_not_empty=sql \u4E0D\u80FD\u70BA\u7A7A
i18n_menu.parameter=\u7CFB\u7D71\u53C3\u6578
i18n_user_old_pwd_error=\u539F\u59CB\u5BC6\u78BC\u932F\u8AA4
i18n_menu.toolbox-log=\u64CD\u4F5C\u65E5\u5FD7
i18n_year=\u5E74
i18n_month=\u6708
@ -63,3 +81,53 @@ i18n_day=\u5929
i18n_hour=\u5C0F\u6642
i18n_minute=\u5206\u9418
i18n_second=\u79D2
i18n_no_datasource_permission_to_create_column=\u7121\u6578\u64DA\u6E90\u8A2A\u554F\u6B0A\u9650\uFF0C\u7121\u6CD5\u5275\u5EFA\u8868\u5B57\u6BB5
i18n_df_folder_cannot_to_search=\u6587\u4EF6\u593E\u4E0D\u80FD\u67E5\u8A62\u6578\u64DA
i18n_df_no_primary_key=\u6C92\u6709\u4E3B\u9375
i18n_df_cannot_operate_folder=\u4E0D\u80FD\u64CD\u4F5C\u6587\u4EF6\u593E
i18n_df_cannot_be_none=[%s] \u4E0D\u80FD\u70BA\u7A7A
i18n_df_value_cannot_be_none=[%s] \u503C: %s \u4E0D\u80FD\u70BA\u7A7A
i18n_df_value_exists_in_database=[%s] \u503C: %s \u5728\u6578\u64DA\u5EAB\u4E2D\u5DF2\u5B58\u5728, \u4E0D\u80FD\u91CD\u5FA9
i18n_df_data=\u6578\u64DA
i18n_df_start=\u958B\u59CB
i18n_df_end=\u7D50\u675F
i18n_df_datasource_not_found=\u6C92\u6709\u627E\u5230\u6578\u64DA\u6E90
i18n_df_datasource_does_not_enable_data_filling=\u8A72\u6578\u64DA\u6E90\u6C92\u6709\u555F\u7528\u6578\u64DA\u586B\u5831\u914D\u7F6E
i18n_df_builtin_datasource=\u5167\u5EFA\u6578\u64DA\u5EAB
i18n_df_folder_required=\u76EE\u9304\u5FC5\u9078
i18n_df_form_not_exists=\u8868\u55AE\u4E0D\u5B58\u5728
i18n_df_name_can_not_empty=\u540D\u7A31\u4E0D\u80FD\u70BA\u7A7A
i18n_df_template=\u6A21\u677F
i18n_df_task_status_is_null_or_finished=\u4EFB\u52D9\u72C0\u614B\u70BA\u7A7A\u6216\u5DF2\u5B8C\u6210
i18n_df_task_need_task_id=\u9700\u6307\u5B9A\u4EFB\u52D9ID
i18n_df_not_current_task_user=\u4E0D\u662F\u7576\u524D\u4EFB\u52D9\u7684\u76EE\u6A19\u7528\u6236
i18n_df_miss_parameter=\u7F3A\u5931\u53C3\u6578
i18n_df_no_running_instance=\u7576\u524D\u4EFB\u52D9\u66AB\u6642\u7121\u904B\u884C\u5BE6\u4F8B
i18n_df_value=\u503C
i18n_df_format_error=\u683C\u5F0F\u89E3\u6790\u932F\u8AA4
i18n_df_cannot_earlier_than=\u4E0D\u80FD\u65E9\u4E8E
i18n_df_cannot_be_all_null=\u4E0D\u80FD\u53EA\u6709\u4E00\u500B\u70BA\u7A7A
i18n_df_value_not_in_range=\u503C\u4E0D\u5728\u8303\u570D\u5167
i18n_df_value_value_not_in_range=\u503C: %s \u4E0D\u5728\u8303\u570D\u5167
i18n_df_required=\u5FC5\u586B
i18n_df_must_unique=\u4E0D\u5141\u8A31\u91CD\u5FA9\u503C
i18n_df_excel_parsing_error=Excel\u89E3\u6790\u932F\u8AA4
i18n_df_excel_is_empty=\u8A72Excel\u6C92\u6709\u6578\u64DA
i18n_df_excel_template_column_not_fit=\u6A21\u677F\u5B57\u6BB5\u500B\u6578\u4E0D\u5339\u914D
i18n_df_selection=\u9078\u9805\u503C\u70BA
i18n_df_date_format=\u65E5\u671F\u683C\u5F0F
i18n_df_integer=\u6574\u5F62\u6578\u5B57
i18n_df_decimal=\u5C0F\u6578\u6578\u5B57
i18n_df_multiple_value_split=\u591A\u500B\u503C\u4F7F\u7528\u5206\u865F";"\u5206\u5272
i18n_df_email_type=\u90F5\u7BB1\u683C\u5F0F
i18n_df_phone_type=\u624B\u6A5F\u865F\u683C\u5F0F
i18n_copilot_cross_ds_error=\u8DE8\u6E90\u6578\u64DA\u96C6\u4E0D\u652F\u6301\u8A72\u529F\u80FD
i18n_template_recommend=\u63A8\u85A6
i18n_template_recent=\u6700\u8FD1\u4F7F\u7528

View File

@ -19,7 +19,9 @@
`ext_label`,
`ext_tooltip`,
`custom_attr`,
`custom_attr_mobile`,
`custom_style`,
`custom_style_mobile`,
`custom_filter`,
`drill_fields`,
`senior`,
@ -59,7 +61,9 @@
`ext_label`,
`ext_tooltip`,
`custom_attr`,
`custom_attr_mobile`,
`custom_style`,
`custom_style_mobile`,
`custom_filter`,
`drill_fields`,
`senior`,
@ -419,4 +423,25 @@
visualization_report_filter
where visualization_report_filter.resource_id = #{dvId} and visualization_report_filter.task_id = #{taskId}
</select>
<delete id="deleteDataVBatch">
DELETE
FROM
data_visualization_info dvi
WHERE
dvi.id IN
<foreach collection="ids" item="id" index="index" open="(" close=")" separator=",">
#{id}
</foreach>
</delete>
<delete id="deleteViewsBatch">
DELETE
FROM
core_chart_view ccv
WHERE
ccv.scene_id IN
<foreach collection="ids" item="id" index="index" open="(" close=")" separator=",">
#{id}
</foreach>
</delete>
</mapper>

View File

@ -1,5 +1,6 @@
import pkg from '../package.json'
import viteCompression from 'vite-plugin-compression'
export default {
plugins: [
viteCompression({
@ -12,6 +13,7 @@ export default {
})
],
build: {
cssCodeSplit: false,
rollupOptions: {
external: id => /de-xpack/.test(id) || /extensions/.test(id),
output: {
@ -19,10 +21,15 @@ export default {
chunkFileNames: `assets/chunk/[name]-${pkg.version}-${pkg.name}.js`,
assetFileNames: `assets/[ext]/[name]-${pkg.version}-${pkg.name}.[ext]`,
entryFileNames: `js/[name]-${pkg.version}-${pkg.name}.js`,
manualChunks(id: string) {
if (id.includes('node_modules')) {
return id.toString().split('node_modules/')[1].split('/')[0].toString()
}
manualChunks: {
echarts: ['echarts'],
vue: ['vue', 'vue-router', 'pinia', 'vue-i18n', 'mitt'],
lodash: ['lodash-es', 'lodash'],
library: ['jspdf', '@tinymce/tinymce-vue', 'screenfull'],
antv: ['@antv/g2', '@antv/g2plot', '@antv/l7', '@antv/l7plot', '@antv/s2'],
tinymce: ['tinymce'],
axios: ['axios'],
'vuedraggable-es': ['vuedraggable']
}
}
},

View File

@ -1,13 +1,16 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/dataease.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title></title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/pages/index/main.ts"></script>
</body>
</html>
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title></title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/pages/index/main.ts"></script>
</body>
</html>

View File

@ -3,10 +3,8 @@
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, viewport-fit=cover" />
<title>DataEase</title>
</head>
<body>
@ -14,4 +12,4 @@
<script type="module" src="/src/pages/mobile/main.ts"></script>
</body>
</html>
</html>

View File

@ -7,7 +7,7 @@
"build:flush": "cd ./flushbonading && rimraf ./demo.html && npm i && node ./index.js",
"ts:check": "vue-tsc --noEmit",
"build:base": "NODE_OPTIONS=--max_old_space_size=4096 vite build --mode base && npm run build:flush",
"build:distributed": "NODE_OPTIONS=--max_old_space_size=4096 vite build --mode distributed && npm run build:flush",
"build:distributed": "NODE_OPTIONS=--max_old_space_size=5020 vite build --mode distributed && npm run build:flush",
"build:lib": "vite build --mode lib",
"lint": "eslint . --ext .vue,.js,.ts,.jsx,.tsx --fix",
"lint:stylelint": "stylelint --fix \"**/*.{vue,less,postcss,css,scss}\" --cache --cache-location node_modules/.cache/stylelint/",

View File

@ -415,5 +415,9 @@ tinymce.addI18n('zh_CN', {
"Whole words": "\u5168\u5b57\u5339\u914d",
"Spellcheck": "\u62fc\u5199\u68c0\u67e5",
"Caption": "\u6807\u9898",
"Insert template": "\u63d2\u5165\u6a21\u677f"
"Insert template": "\u63d2\u5165\u6a21\u677f",
"Cut column": "\u526a\u5207\u5217",
"Copy column": "\u590d\u5236\u5217",
"Paste column before": "\u7c98\u8d34\u5230\u524d\u65b9",
"Paste column after": "\u7c98\u8d34\u5230\u540e\u65b9"
});

View File

@ -88,7 +88,7 @@ export const saveChart = async (data): Promise<IResponse> => {
}
// 获取单个字段枚举值
export const getFieldData = async (fieldId, fieldType, data): Promise<IResponse> => {
export const getFieldData = async ({ fieldId, fieldType, data }): Promise<IResponse> => {
delete data.data
return request
.post({ url: `/chartData/getFieldData/${fieldId}/${fieldType}`, data })
@ -97,6 +97,14 @@ export const getFieldData = async (fieldId, fieldType, data): Promise<IResponse>
})
}
// 获取下钻字段枚举值
export const getDrillFieldData = async ({ fieldId, data }): Promise<IResponse> => {
delete data.data
return request.post({ url: `/chartData/getDrillFieldData/${fieldId}`, data }).then(res => {
return res
})
}
export const getChartDetail = async (id: string): Promise<IResponse> => {
return request.post({ url: `chart/getDetail/${id}`, data: {} }).then(res => {
return res

View File

@ -32,6 +32,8 @@ export const queryFormApi = uid => request.get({ url: `/user/queryById/${uid}` }
export const personInfoApi = () => request.get({ url: `/user/personInfo` })
export const ipInfoApi = () => request.get({ url: `/user/ipInfo` })
export const roleCreateApi = data => request.post({ url: '/role/create', data })
export const roleEditApi = data => request.post({ url: '/role/edit', data })

View File

@ -41,6 +41,12 @@ export const queryTreeApi = async (data: BusiTreeRequest): Promise<IResponse> =>
})
}
export const queryBusiTreeApi = async (data): Promise<IResponse> => {
return request.post({ url: '/dataVisualization/interactiveTree', data }).then(res => {
return res?.data
})
}
export const findDvType = async dvId =>
request.get({ url: `/dataVisualization/findDvType/${dvId}` })
@ -115,3 +121,10 @@ export const queryOuterParamsDsInfo = async dvId => {
loading: false
})
}
export const queryShareBaseApi = () => {
return request.get({
url: '/sysParameter/shareBase',
loading: false
})
}

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 742 KiB

After

Width:  |  Height:  |  Size: 61 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 739 KiB

After

Width:  |  Height:  |  Size: 62 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 742 KiB

After

Width:  |  Height:  |  Size: 61 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.2 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 741 KiB

After

Width:  |  Height:  |  Size: 62 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 739 KiB

After

Width:  |  Height:  |  Size: 64 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 742 KiB

After

Width:  |  Height:  |  Size: 62 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 744 KiB

After

Width:  |  Height:  |  Size: 62 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 739 KiB

After

Width:  |  Height:  |  Size: 64 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 744 KiB

After

Width:  |  Height:  |  Size: 62 KiB

View File

@ -1 +1,3 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1715769658859" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4704" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M1023.853735 948.673618v75.25325H596.248536V948.673618zM511.926868 0.073132a511.926868 511.926868 0 0 1 511.926867 511.926868h-75.253249a436.600486 436.600486 0 1 0-436.600486 436.600486h5.119269v75.253249h-5.119269a511.926868 511.926868 0 1 1 0-1023.853735z m511.926867 803.505785v75.25325H596.248536v-75.180117zM362.590487 290.116269l192.11884 110.941866 192.11884 110.941865-192.11884 110.941865-192.11884 110.941866V290.189402zM1023.853735 658.484217v75.399514H596.248536V658.630481zM437.843737 420.438223v182.831024l79.202399-45.780888 79.2024-45.707756-79.2024-45.707756z" p-id="4705"></path></svg>
<svg width="40" height="40" viewBox="0 0 40 40" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M36.6667 5C37.5871 5 38.3333 5.83947 38.3333 6.875V33.125C38.3333 34.1605 37.5871 35 36.6667 35H3.33333C2.41286 35 1.66667 34.1605 1.66667 33.125V6.875C1.66667 5.83947 2.41286 5 3.33333 5H36.6667ZM14.3426 25.5486C14.7543 26.3719 15.7554 26.7057 16.5787 26.294L26.1853 21.4907C26.5078 21.3295 26.7693 21.0679 26.9306 20.7454C27.3423 19.9221 27.0086 18.9209 26.1853 18.5093L16.5787 13.706C16.3473 13.5903 16.0921 13.5301 15.8333 13.5301C14.9129 13.5301 14.1667 14.2763 14.1667 15.1967V24.8033C14.1667 25.062 14.2269 25.3172 14.3426 25.5486ZM10 9.16667H6.66667V14.1667H10V9.16667ZM10 17.5H6.66667V22.5H10V17.5ZM10 25.8333H6.66667V30.8333H10V25.8333ZM33.3333 9.16667H30V14.1667H33.3333V9.16667ZM30 17.5H33.3333V22.5H30V17.5ZM30 25.8333H33.3333V30.8333H30V25.8333Z" />
</svg>

Before

Width:  |  Height:  |  Size: 938 B

After

Width:  |  Height:  |  Size: 904 B

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 715 B

View File

@ -1,4 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2.85738 4.85729L9.98911 11.989L2.85738 19.1207C2.66212 19.316 2.66212 19.6326 2.85738 19.8279L3.56449 20.535C3.75975 20.7302 4.07634 20.7302 4.2716 20.535L12.1104 12.6961C12.501 12.3056 12.501 11.6724 12.1104 11.2819L4.2716 3.44308C4.07634 3.24782 3.75975 3.24782 3.56449 3.44308L2.85738 4.15018C2.66212 4.34545 2.66212 4.66203 2.85738 4.85729Z" fill="#1F2329"/>
<path d="M11.7431 4.85729L18.8749 11.989L11.7431 19.1207C11.5479 19.316 11.5479 19.6326 11.7431 19.8279L12.4502 20.535C12.6455 20.7302 12.9621 20.7302 13.1573 20.535L20.9962 12.6961C21.3867 12.3056 21.3867 11.6724 20.9962 11.2819L13.1573 3.44308C12.9621 3.24782 12.6455 3.24782 12.4502 3.44308L11.7431 4.15018C11.5479 4.34545 11.5479 4.66203 11.7431 4.85729Z" fill="#1F2329"/>
<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M2.85738 4.85729L9.98911 11.989L2.85738 19.1207C2.66212 19.316 2.66212 19.6326 2.85738 19.8279L3.56449 20.535C3.75975 20.7302 4.07634 20.7302 4.2716 20.535L12.1104 12.6961C12.501 12.3056 12.501 11.6724 12.1104 11.2819L4.2716 3.44308C4.07634 3.24782 3.75975 3.24782 3.56449 3.44308L2.85738 4.15018C2.66212 4.34545 2.66212 4.66203 2.85738 4.85729Z" />
<path d="M11.7431 4.85729L18.8749 11.989L11.7431 19.1207C11.5479 19.316 11.5479 19.6326 11.7431 19.8279L12.4502 20.535C12.6455 20.7302 12.9621 20.7302 13.1573 20.535L20.9962 12.6961C21.3867 12.3056 21.3867 11.6724 20.9962 11.2819L13.1573 3.44308C12.9621 3.24782 12.6455 3.24782 12.4502 3.44308L11.7431 4.15018C11.5479 4.34545 11.5479 4.66203 11.7431 4.85729Z"/>
</svg>

Before

Width:  |  Height:  |  Size: 853 B

After

Width:  |  Height:  |  Size: 812 B

View File

@ -1,3 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M21 18.5V21C21 21.5523 20.5523 22 20 22H4C3.44772 22 3 21.5523 3 21V18.5C3 18.2239 3.22386 18 3.5 18H4.5C4.77614 18 5 18.2239 5 18.5V20H19V18.5C19 18.2239 19.2239 18 19.5 18H20.5C20.7761 18 21 18.2239 21 18.5ZM13 14.0357L16.0105 11.0252C16.2057 10.83 16.5223 10.83 16.7176 11.0252L17.4247 11.7324C17.6199 11.9276 17.6199 12.2442 17.4247 12.4395L12.4749 17.3892C12.3773 17.4868 12.2493 17.5357 12.1214 17.5357C11.9934 17.5357 11.8655 17.4868 11.7678 17.3892L6.81808 12.4395C6.62282 12.2442 6.62282 11.9276 6.81808 11.7324L7.52519 11.0252C7.72045 10.83 8.03703 10.83 8.2323 11.0252L11 13.793V3C11 2.72386 11.2239 2.5 11.5 2.5H12.5C12.7761 2.5 13 2.72386 13 3V14.0357Z" fill="#1F2329"/>
<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M21 18.5V21C21 21.5523 20.5523 22 20 22H4C3.44772 22 3 21.5523 3 21V18.5C3 18.2239 3.22386 18 3.5 18H4.5C4.77614 18 5 18.2239 5 18.5V20H19V18.5C19 18.2239 19.2239 18 19.5 18H20.5C20.7761 18 21 18.2239 21 18.5ZM13 14.0357L16.0105 11.0252C16.2057 10.83 16.5223 10.83 16.7176 11.0252L17.4247 11.7324C17.6199 11.9276 17.6199 12.2442 17.4247 12.4395L12.4749 17.3892C12.3773 17.4868 12.2493 17.5357 12.1214 17.5357C11.9934 17.5357 11.8655 17.4868 11.7678 17.3892L6.81808 12.4395C6.62282 12.2442 6.62282 11.9276 6.81808 11.7324L7.52519 11.0252C7.72045 10.83 8.03703 10.83 8.2323 11.0252L11 13.793V3C11 2.72386 11.2239 2.5 11.5 2.5H12.5C12.7761 2.5 13 2.72386 13 3V14.0357Z"/>
</svg>

Before

Width:  |  Height:  |  Size: 796 B

After

Width:  |  Height:  |  Size: 769 B

View File

@ -1,3 +1,3 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7.1518 11.5968C7.31452 11.4341 7.57834 11.4341 7.74106 11.5968L8.33031 12.186C8.49303 12.3487 8.49303 12.6126 8.33031 12.7753L4.99587 16.1086H7.36621C7.59633 16.1086 7.78288 16.2952 7.78288 16.5253V17.3586C7.78288 17.5887 7.59633 17.7753 7.36621 17.7753H3.05555C2.82544 17.7753 2.6171 17.682 2.4663 17.5312C2.3155 17.3804 2.22222 17.1721 2.22222 16.9419V12.6421C2.22222 12.412 2.40877 12.2255 2.63889 12.2255H3.47222C3.70234 12.2255 3.88889 12.412 3.88889 12.6421V14.8586L7.1518 11.5968ZM16.9367 2.22217C17.1668 2.22217 17.3751 2.31544 17.5259 2.46625C17.6767 2.61705 17.77 2.82538 17.77 3.0555V7.35531C17.77 7.58543 17.5835 7.77198 17.3533 7.77198H16.52C16.2899 7.77198 16.1033 7.58543 16.1033 7.35531V5.13888L12.8404 8.40068C12.6777 8.5634 12.4139 8.5634 12.2512 8.40068L11.6619 7.81142C11.4992 7.6487 11.4992 7.38489 11.6619 7.22217L14.9964 3.88883H12.626C12.3959 3.88883 12.2094 3.70229 12.2094 3.47217V2.63883C12.2094 2.40872 12.3959 2.22217 12.626 2.22217H16.9367Z" fill="#1F2329"/>
<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
<path d="M7.1518 11.5968C7.31452 11.4341 7.57834 11.4341 7.74106 11.5968L8.33031 12.186C8.49303 12.3487 8.49303 12.6126 8.33031 12.7753L4.99587 16.1086H7.36621C7.59633 16.1086 7.78288 16.2952 7.78288 16.5253V17.3586C7.78288 17.5887 7.59633 17.7753 7.36621 17.7753H3.05555C2.82544 17.7753 2.6171 17.682 2.4663 17.5312C2.3155 17.3804 2.22222 17.1721 2.22222 16.9419V12.6421C2.22222 12.412 2.40877 12.2255 2.63889 12.2255H3.47222C3.70234 12.2255 3.88889 12.412 3.88889 12.6421V14.8586L7.1518 11.5968ZM16.9367 2.22217C17.1668 2.22217 17.3751 2.31544 17.5259 2.46625C17.6767 2.61705 17.77 2.82538 17.77 3.0555V7.35531C17.77 7.58543 17.5835 7.77198 17.3533 7.77198H16.52C16.2899 7.77198 16.1033 7.58543 16.1033 7.35531V5.13888L12.8404 8.40068C12.6777 8.5634 12.4139 8.5634 12.2512 8.40068L11.6619 7.81142C11.4992 7.6487 11.4992 7.38489 11.6619 7.22217L14.9964 3.88883H12.626C12.3959 3.88883 12.2094 3.70229 12.2094 3.47217V2.63883C12.2094 2.40872 12.3959 2.22217 12.626 2.22217H16.9367Z" />
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -1,3 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.00839 13.9974C9.28453 13.9974 9.53453 14.1093 9.71549 14.2903C9.89646 14.4712 10.0084 14.7212 10.0084 14.9974V20.1572C10.0084 20.4333 9.78453 20.6572 9.50839 20.6572H8.50839C8.23224 20.6572 8.00839 20.4333 8.00839 20.1572V17.4974L4.09289 21.4116C3.89762 21.6069 3.58104 21.6069 3.38578 21.4116L2.67867 20.7045C2.48341 20.5092 2.48341 20.1927 2.67867 19.9974L6.68001 15.9974H3.83559C3.55945 15.9974 3.33559 15.7735 3.33559 15.4974V14.4974C3.33559 14.2212 3.55945 13.9974 3.83559 13.9974H9.00839ZM19.919 2.58865C20.1142 2.39338 20.4308 2.39338 20.6261 2.58865L21.3332 3.29575C21.5284 3.49102 21.5284 3.8076 21.3332 4.00286L17.3318 8.00286H20.1763C20.4524 8.00286 20.6763 8.22672 20.6763 8.50286V9.50286C20.6763 9.779 20.4524 10.0029 20.1763 10.0029H15.0035C14.7273 10.0029 14.4773 9.89093 14.2964 9.70997C14.1154 9.529 14.0035 9.279 14.0035 9.00286V3.84309C14.0035 3.56695 14.2273 3.34309 14.5035 3.34309H15.5035C15.7796 3.34309 16.0035 3.56695 16.0035 3.84309V6.50281L19.919 2.58865Z" fill="#1F2329"/>
<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M9.00839 13.9974C9.28453 13.9974 9.53453 14.1093 9.71549 14.2903C9.89646 14.4712 10.0084 14.7212 10.0084 14.9974V20.1572C10.0084 20.4333 9.78453 20.6572 9.50839 20.6572H8.50839C8.23224 20.6572 8.00839 20.4333 8.00839 20.1572V17.4974L4.09289 21.4116C3.89762 21.6069 3.58104 21.6069 3.38578 21.4116L2.67867 20.7045C2.48341 20.5092 2.48341 20.1927 2.67867 19.9974L6.68001 15.9974H3.83559C3.55945 15.9974 3.33559 15.7735 3.33559 15.4974V14.4974C3.33559 14.2212 3.55945 13.9974 3.83559 13.9974H9.00839ZM19.919 2.58865C20.1142 2.39338 20.4308 2.39338 20.6261 2.58865L21.3332 3.29575C21.5284 3.49102 21.5284 3.8076 21.3332 4.00286L17.3318 8.00286H20.1763C20.4524 8.00286 20.6763 8.22672 20.6763 8.50286V9.50286C20.6763 9.779 20.4524 10.0029 20.1763 10.0029H15.0035C14.7273 10.0029 14.4773 9.89093 14.2964 9.70997C14.1154 9.529 14.0035 9.279 14.0035 9.00286V3.84309C14.0035 3.56695 14.2273 3.34309 14.5035 3.34309H15.5035C15.7796 3.34309 16.0035 3.56695 16.0035 3.84309V6.50281L19.919 2.58865Z" />
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Some files were not shown because too many files have changed in this diff Show More