Merge branch 'dev-v2' of github.com:dataease/dataease into dev-v2
@ -250,6 +250,120 @@ public class DefaultChartHandler extends AbstractChartPlugin {
|
||||
return res;
|
||||
}
|
||||
|
||||
protected List<ChartViewFieldDTO> getAssistFields(List<ChartSeniorAssistDTO> list, List<ChartViewFieldDTO> yAxis, List<ChartViewFieldDTO> xAxis) {
|
||||
List<ChartViewFieldDTO> res = new ArrayList<>();
|
||||
for (ChartSeniorAssistDTO dto : list) {
|
||||
DatasetTableFieldDTO curField = dto.getCurField();
|
||||
ChartViewFieldDTO field = null;
|
||||
String alias = "";
|
||||
for (int i = 0; i < yAxis.size(); i++) {
|
||||
ChartViewFieldDTO yField = yAxis.get(i);
|
||||
if (Objects.equals(yField.getId(), curField.getId())) {
|
||||
field = yField;
|
||||
alias = String.format(SQLConstants.FIELD_ALIAS_Y_PREFIX, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ObjectUtils.isEmpty(field) && CollectionUtils.isNotEmpty(xAxis)) {
|
||||
for (int i = 0; i < xAxis.size(); i++) {
|
||||
ChartViewFieldDTO xField = xAxis.get(i);
|
||||
if (StringUtils.equalsIgnoreCase(String.valueOf(xField.getId()), String.valueOf(curField.getId()))) {
|
||||
field = xField;
|
||||
alias = String.format(SQLConstants.FIELD_ALIAS_X_PREFIX, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ObjectUtils.isEmpty(field)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ChartViewFieldDTO chartViewFieldDTO = new ChartViewFieldDTO();
|
||||
BeanUtils.copyBean(chartViewFieldDTO, curField);
|
||||
chartViewFieldDTO.setSummary(dto.getSummary());
|
||||
chartViewFieldDTO.setOriginName(alias);// yAxis的字段别名,就是查找的字段名
|
||||
res.add(chartViewFieldDTO);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public List<ChartSeniorAssistDTO> getDynamicThresholdFields(ChartViewDTO view) {
|
||||
List<ChartSeniorAssistDTO> list = new ArrayList<>();
|
||||
Map<String, Object> senior = view.getSenior();
|
||||
if (ObjectUtils.isEmpty(senior)) {
|
||||
return list;
|
||||
}
|
||||
ChartSeniorThresholdCfgDTO thresholdCfg = JsonUtil.parseObject((String) JsonUtil.toJSONString(senior.get("threshold")), ChartSeniorThresholdCfgDTO.class);
|
||||
|
||||
if (null == thresholdCfg || !thresholdCfg.isEnable()) {
|
||||
return list;
|
||||
}
|
||||
List<TableThresholdDTO> tableThreshold = thresholdCfg.getTableThreshold();
|
||||
|
||||
if (ObjectUtils.isEmpty(tableThreshold)) {
|
||||
return list;
|
||||
}
|
||||
|
||||
List<ChartSeniorThresholdDTO> conditionsList = tableThreshold.stream()
|
||||
.filter(item -> !ObjectUtils.isEmpty(item))
|
||||
.map(TableThresholdDTO::getConditions)
|
||||
.flatMap(List::stream)
|
||||
.filter(condition -> StringUtils.equalsAnyIgnoreCase(condition.getType(), "dynamic"))
|
||||
.toList();
|
||||
|
||||
List<ChartSeniorAssistDTO> assistDTOs = conditionsList.stream()
|
||||
.flatMap(condition -> getConditionFields(condition).stream())
|
||||
.filter(this::solveThresholdCondition)
|
||||
.toList();
|
||||
|
||||
list.addAll(assistDTOs);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
private boolean solveThresholdCondition(ChartSeniorAssistDTO fieldDTO) {
|
||||
Long fieldId = fieldDTO.getFieldId();
|
||||
String summary = fieldDTO.getValue();
|
||||
if (ObjectUtils.isEmpty(fieldId) || StringUtils.isEmpty(summary)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DatasetTableFieldDTO datasetTableFieldDTO = datasetTableFieldManage.selectById(fieldId);
|
||||
if (ObjectUtils.isEmpty(datasetTableFieldDTO)) {
|
||||
return false;
|
||||
}
|
||||
ChartViewFieldDTO datasetTableField = new ChartViewFieldDTO();
|
||||
BeanUtils.copyBean(datasetTableField, datasetTableFieldDTO);
|
||||
fieldDTO.setCurField(datasetTableField);
|
||||
fieldDTO.setSummary(summary);
|
||||
return true;
|
||||
}
|
||||
|
||||
private List<ChartSeniorAssistDTO> getConditionFields(ChartSeniorThresholdDTO condition) {
|
||||
List<ChartSeniorAssistDTO> list = new ArrayList<>();
|
||||
if ("between".equals(condition.getTerm())) {
|
||||
if (!StringUtils.equalsIgnoreCase(condition.getDynamicMaxField().getSummary(), "value")) {
|
||||
list.add(of(condition.getDynamicMaxField()));
|
||||
}
|
||||
if (!StringUtils.equalsIgnoreCase(condition.getDynamicMinField().getSummary(), "value")) {
|
||||
list.add(of(condition.getDynamicMinField()));
|
||||
}
|
||||
} else {
|
||||
if (!StringUtils.equalsIgnoreCase(condition.getDynamicField().getSummary(), "value")) {
|
||||
list.add(of(condition.getDynamicField()));
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
private ChartSeniorAssistDTO of(ThresholdDynamicFieldDTO dynamicField){
|
||||
ChartSeniorAssistDTO conditionField = new ChartSeniorAssistDTO();
|
||||
conditionField.setFieldId(Long.parseLong(dynamicField.getFieldId()));
|
||||
conditionField.setValue(dynamicField.getSummary());
|
||||
return conditionField;
|
||||
}
|
||||
|
||||
protected String assistSQL(String sql, List<ChartViewFieldDTO> assistFields) {
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
for (int i = 0; i < assistFields.size(); i++) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 {
|
||||
@ -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);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
@ -35,6 +36,25 @@ public class TablePivotHandler extends GroupChartHandler {
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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"));
|
||||
|
@ -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";
|
||||
}
|
||||
|
@ -129,6 +129,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 +194,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 +209,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 +241,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<>();
|
||||
|
@ -494,7 +494,16 @@ public class DatasetSQLManage {
|
||||
datasourceSchemaDTO.setSchemaAlias(schemaAlias);
|
||||
dsMap.put(coreDatasource.getId(), datasourceSchemaDTO);
|
||||
}
|
||||
} else {
|
||||
} 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);
|
||||
datasourceSchemaDTO.setSchemaAlias(schemaAlias);
|
||||
dsMap.put(coreDatasource.getId(), datasourceSchemaDTO);
|
||||
}
|
||||
}else {
|
||||
CoreDatasource coreDatasource = engineManage.getDeEngine();
|
||||
schemaAlias = String.format(SQLConstants.SCHEMA, coreDatasource.getId());
|
||||
if (!dsMap.containsKey(coreDatasource.getId())) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
package io.dataease.datasource.dto.es;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class RequestWithCursor extends Request {
|
||||
private String cursor;
|
||||
}
|
@ -1271,7 +1271,6 @@ public class CalciteProvider extends Provider {
|
||||
try {
|
||||
connection = initConnection(dsMap);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -0,0 +1,211 @@
|
||||
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("dataList", fetchResultData(response));
|
||||
result.put("fieldList", 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 response = execQuery(datasourceRequest, "select * from " + datasourceRequest.getTable() + " limit 0", "?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);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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;
|
||||
|
||||
}
|
Before Width: | Height: | Size: 742 KiB After Width: | Height: | Size: 61 KiB |
Before Width: | Height: | Size: 739 KiB After Width: | Height: | Size: 62 KiB |
Before Width: | Height: | Size: 742 KiB After Width: | Height: | Size: 61 KiB |
1
core/core-frontend/src/assets/svg/es-ds.svg
Normal file
After Width: | Height: | Size: 6.2 KiB |
Before Width: | Height: | Size: 741 KiB After Width: | Height: | Size: 62 KiB |
Before Width: | Height: | Size: 739 KiB After Width: | Height: | Size: 64 KiB |
Before Width: | Height: | Size: 742 KiB After Width: | Height: | Size: 62 KiB |
Before Width: | Height: | Size: 744 KiB After Width: | Height: | Size: 62 KiB |
Before Width: | Height: | Size: 739 KiB After Width: | Height: | Size: 64 KiB |
Before Width: | Height: | Size: 744 KiB After Width: | Height: | Size: 62 KiB |
Before Width: | Height: | Size: 739 KiB After Width: | Height: | Size: 147 KiB |
Before Width: | Height: | Size: 739 KiB After Width: | Height: | Size: 97 KiB |
Before Width: | Height: | Size: 739 KiB After Width: | Height: | Size: 147 KiB |
Before Width: | Height: | Size: 742 KiB After Width: | Height: | Size: 63 KiB |
Before Width: | Height: | Size: 739 KiB After Width: | Height: | Size: 65 KiB |
Before Width: | Height: | Size: 742 KiB After Width: | Height: | Size: 63 KiB |
@ -13,6 +13,7 @@ import redshiftDs from '@/assets/svg/redshift-ds.svg'
|
||||
import APIDs from '@/assets/svg/API-ds.svg'
|
||||
import ExcelDs from '@/assets/svg/Excel-ds.svg'
|
||||
import dorisDs from '@/assets/svg/doris-ds.svg'
|
||||
import esDs from '@/assets/svg/es-ds.svg'
|
||||
const iconDatasourceMap = {
|
||||
mysql: mysqlDs,
|
||||
oracle: oracleDs,
|
||||
@ -28,7 +29,8 @@ const iconDatasourceMap = {
|
||||
redshift: redshiftDs,
|
||||
API: APIDs,
|
||||
Excel: ExcelDs,
|
||||
doris: dorisDs
|
||||
doris: dorisDs,
|
||||
es: esDs
|
||||
}
|
||||
|
||||
export { iconDatasourceMap }
|
||||
|
@ -111,6 +111,27 @@ const btnStyle = computed(() => {
|
||||
|
||||
return style
|
||||
})
|
||||
|
||||
const btnPlainStyle = computed(() => {
|
||||
const style = {
|
||||
backgroundColor: 'transparent',
|
||||
borderColor: customStyle.btnColor,
|
||||
color: customStyle.btnColor
|
||||
} as CSSProperties
|
||||
if (customStyle.fontSizeBtn) {
|
||||
style.fontSize = customStyle.fontSizeBtn + 'px'
|
||||
}
|
||||
|
||||
if (customStyle.fontWeightBtn) {
|
||||
style.fontWeight = customStyle.fontWeightBtn
|
||||
}
|
||||
|
||||
if (customStyle.fontStyleBtn) {
|
||||
style.fontStyle = customStyle.fontStyleBtn
|
||||
}
|
||||
|
||||
return style
|
||||
})
|
||||
const curComponentView = computed(() => {
|
||||
return (canvasViewInfo.value[element.value.id] || {}).customStyle
|
||||
})
|
||||
@ -619,10 +640,20 @@ const autoStyle = computed(() => {
|
||||
</div>
|
||||
</div>
|
||||
<div class="query-button" v-if="!!listVisible.length">
|
||||
<el-button @click.stop="clearData" v-if="customStyle.btnList.includes('clear')" secondary>
|
||||
<el-button
|
||||
@click.stop="clearData"
|
||||
:style="btnPlainStyle"
|
||||
v-if="customStyle.btnList.includes('clear')"
|
||||
plain
|
||||
>
|
||||
{{ t('commons.clear') }}
|
||||
</el-button>
|
||||
<el-button @click.stop="resetData" v-if="customStyle.btnList.includes('reset')" secondary>
|
||||
<el-button
|
||||
@click.stop="resetData"
|
||||
:style="btnPlainStyle"
|
||||
v-if="customStyle.btnList.includes('reset')"
|
||||
plain
|
||||
>
|
||||
{{ t('chart.reset') }}
|
||||
</el-button>
|
||||
<el-button
|
||||
|
@ -365,7 +365,11 @@ export default {
|
||||
please_insert_end: 'End Time Column Name',
|
||||
save_form: 'Save Form',
|
||||
default: 'default',
|
||||
default_built_in: 'Built-in Database'
|
||||
default_built_in: 'Built-in Database',
|
||||
lt_check: 'need less than {0}',
|
||||
gt_check: 'need greater than {0}',
|
||||
le_check: 'need less than or equal to {0}',
|
||||
ge_check: 'need greater than or equal to {0}'
|
||||
},
|
||||
database: {
|
||||
nvarchar: 'Nvarchar',
|
||||
|
@ -266,7 +266,11 @@ export default {
|
||||
please_insert_end: '請輸入結束時間',
|
||||
save_form: '保存表單',
|
||||
default: '默認',
|
||||
default_built_in: '內建數據庫'
|
||||
default_built_in: '內建數據庫',
|
||||
lt_check: '值需要小于{0}',
|
||||
gt_check: '值需要大于{0}',
|
||||
le_check: '值需要小于等于{0}',
|
||||
ge_check: '值需要大于等于{0}'
|
||||
},
|
||||
database: {
|
||||
nvarchar: '字符串',
|
||||
|
@ -2703,7 +2703,11 @@ export default {
|
||||
please_insert_end: '请输入结束时间',
|
||||
save_form: '保存表单',
|
||||
default: '默认',
|
||||
default_built_in: '内建数据库'
|
||||
default_built_in: '内建数据库',
|
||||
lt_check: '值需要小于{0}',
|
||||
gt_check: '值需要大于{0}',
|
||||
le_check: '值需要小于等于{0}',
|
||||
ge_check: '值需要大于等于{0}'
|
||||
},
|
||||
database: {
|
||||
nvarchar: '字符串',
|
||||
|
@ -198,6 +198,28 @@ declare interface Threshold {
|
||||
* url
|
||||
*/
|
||||
url: string
|
||||
/**
|
||||
* 类型,固定值、动态值
|
||||
*/
|
||||
type: 'fixed' | 'dynamic'
|
||||
/**
|
||||
* 动态值字段
|
||||
*/
|
||||
dynamicField: ThresholdDynamicField
|
||||
/**
|
||||
* 动态值最小值字段 仅当term为between时使用
|
||||
*/
|
||||
dynamicMinField: ThresholdDynamicField
|
||||
/**
|
||||
* 动态值最大值字段 仅当term为between时使用
|
||||
*/
|
||||
dynamicMaxField: ThresholdDynamicField
|
||||
}
|
||||
|
||||
declare interface ThresholdDynamicField {
|
||||
fieldId: string
|
||||
summary: string
|
||||
field: ChartViewField
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -193,40 +193,62 @@ const changeTableThreshold = () => {
|
||||
ElMessage.error(t('chart.exp_can_not_empty'))
|
||||
return
|
||||
}
|
||||
if (ele.term === 'between') {
|
||||
if (
|
||||
!ele.term.includes('null') &&
|
||||
!ele.term.includes('empty') &&
|
||||
(ele.min === '' || ele.max === '')
|
||||
) {
|
||||
ElMessage.error(t('chart.value_can_not_empty'))
|
||||
return
|
||||
}
|
||||
if (
|
||||
(field.field.deType === 2 || field.field.deType === 3 || field.field.deType === 4) &&
|
||||
(parseFloat(ele.min).toString() === 'NaN' || parseFloat(ele.max).toString() === 'NaN')
|
||||
) {
|
||||
ElMessage.error(t('chart.value_error'))
|
||||
return
|
||||
}
|
||||
if (
|
||||
(field.field.deType === 2 || field.field.deType === 3 || field.field.deType === 4) &&
|
||||
parseFloat(ele.min) > parseFloat(ele.max)
|
||||
) {
|
||||
ElMessage.error(t('chart.value_min_max_invalid'))
|
||||
return
|
||||
if (ele.type !== 'dynamic') {
|
||||
if (ele.term === 'between') {
|
||||
if (
|
||||
!ele.term.includes('null') &&
|
||||
!ele.term.includes('empty') &&
|
||||
(ele.min === '' || ele.max === '')
|
||||
) {
|
||||
ElMessage.error(t('chart.value_can_not_empty'))
|
||||
return
|
||||
}
|
||||
if (
|
||||
(field.field.deType === 2 || field.field.deType === 3 || field.field.deType === 4) &&
|
||||
(parseFloat(ele.min).toString() === 'NaN' || parseFloat(ele.max).toString() === 'NaN')
|
||||
) {
|
||||
ElMessage.error(t('chart.value_error'))
|
||||
return
|
||||
}
|
||||
if (
|
||||
(field.field.deType === 2 || field.field.deType === 3 || field.field.deType === 4) &&
|
||||
parseFloat(ele.min) > parseFloat(ele.max)
|
||||
) {
|
||||
ElMessage.error(t('chart.value_min_max_invalid'))
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if (!ele.term.includes('null') && !ele.term.includes('empty') && ele.value === '') {
|
||||
ElMessage.error(t('chart.value_can_not_empty'))
|
||||
return
|
||||
}
|
||||
if (
|
||||
(field.field.deType === 2 || field.field.deType === 3 || field.field.deType === 4) &&
|
||||
parseFloat(ele.value).toString() === 'NaN'
|
||||
) {
|
||||
ElMessage.error(t('chart.value_error'))
|
||||
return
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!ele.term.includes('null') && !ele.term.includes('empty') && ele.value === '') {
|
||||
ElMessage.error(t('chart.value_can_not_empty'))
|
||||
return
|
||||
}
|
||||
if (
|
||||
(field.field.deType === 2 || field.field.deType === 3 || field.field.deType === 4) &&
|
||||
parseFloat(ele.value).toString() === 'NaN'
|
||||
) {
|
||||
ElMessage.error(t('chart.value_error'))
|
||||
return
|
||||
if (ele.term === 'between') {
|
||||
if (
|
||||
!ele.term.includes('null') &&
|
||||
!ele.term.includes('empty') &&
|
||||
(!ele.dynamicMinField?.fieldId || !ele.dynamicMaxField?.fieldId)
|
||||
) {
|
||||
ElMessage.error(t('chart.field_can_not_empty'))
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if (
|
||||
!ele.term.includes('null') &&
|
||||
!ele.term.includes('empty') &&
|
||||
!ele.dynamicField?.fieldId
|
||||
) {
|
||||
ElMessage.error(t('chart.field_can_not_empty'))
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -235,7 +257,24 @@ const changeTableThreshold = () => {
|
||||
changeThreshold()
|
||||
closeTableThreshold()
|
||||
}
|
||||
const getFieldName = field => (field.chartShowName ? field.chartShowName : field.name)
|
||||
|
||||
const getDynamicStyleLabel = (item, fieldObj) => {
|
||||
const handleSummary = field => {
|
||||
if (!field?.field) {
|
||||
return ''
|
||||
}
|
||||
if (field.summary === 'value') {
|
||||
return getFieldName(field.field) + '(' + t('chart.field') + ')'
|
||||
} else {
|
||||
let suffix = field.summary === 'avg' ? t('chart.drag_block_label_value') : ''
|
||||
return getFieldName(field.field) + '(' + t('chart.' + field.summary) + suffix + ')'
|
||||
}
|
||||
}
|
||||
if (item.type === 'dynamic') {
|
||||
return handleSummary(fieldObj)
|
||||
}
|
||||
}
|
||||
init()
|
||||
</script>
|
||||
|
||||
@ -519,17 +558,15 @@ init()
|
||||
style="flex-direction: column"
|
||||
>
|
||||
<div class="field-style" :class="{ 'field-style-dark': themes === 'dark' }">
|
||||
<span>
|
||||
<el-icon>
|
||||
<Icon :className="`field-icon-${fieldType[fieldItem.field.deType]}`"
|
||||
><component
|
||||
class="svg-icon"
|
||||
:class="`field-icon-${fieldType[fieldItem.field.deType]}`"
|
||||
:is="iconFieldMap[fieldType[fieldItem.field.deType]]"
|
||||
></component
|
||||
></Icon>
|
||||
</el-icon>
|
||||
</span>
|
||||
<el-icon>
|
||||
<Icon :className="`field-icon-${fieldType[fieldItem.field.deType]}`"
|
||||
><component
|
||||
class="svg-icon"
|
||||
:class="`field-icon-${fieldType[fieldItem.field.deType]}`"
|
||||
:is="iconFieldMap[fieldType[fieldItem.field.deType]]"
|
||||
></component
|
||||
></Icon>
|
||||
</el-icon>
|
||||
<span :title="fieldItem.field.name" class="field-text">{{
|
||||
fieldItem.field.name
|
||||
}}</span>
|
||||
@ -577,7 +614,17 @@ init()
|
||||
</span>
|
||||
<span v-else-if="item.term === 'default'" title="默认"> 默认 </span>
|
||||
</div>
|
||||
<div style="flex: 1; margin: 0 8px">
|
||||
<div v-if="item.type !== 'dynamic'" style="flex: 1; margin: 0 8px">
|
||||
<span style="margin: 0 8px">
|
||||
{{ t('chart.fix') }}
|
||||
</span>
|
||||
</div>
|
||||
<div v-else style="flex: 1; margin: 0 8px">
|
||||
<span style="margin: 0 8px">
|
||||
{{ t('chart.dynamic') }}
|
||||
</span>
|
||||
</div>
|
||||
<div v-if="item.type !== 'dynamic'" style="flex: 1; margin: 0 8px">
|
||||
<span
|
||||
v-if="
|
||||
!item.term.includes('null') &&
|
||||
@ -594,11 +641,44 @@ init()
|
||||
!item.term.includes('empty') &&
|
||||
item.term === 'between'
|
||||
"
|
||||
:title="item.min + ' ≤= ' + t('chart.drag_block_label_value') + ' ≤ ' + item.max"
|
||||
>
|
||||
{{ item.min }} ≤{{ t('chart.drag_block_label_value') }}≤ {{ item.max }}
|
||||
</span>
|
||||
<span v-else> </span>
|
||||
</div>
|
||||
<div v-else style="flex: 1; margin: 0 8px">
|
||||
<span
|
||||
v-if="
|
||||
!item.term.includes('null') &&
|
||||
!item.term.includes('default') &&
|
||||
!item.term.includes('empty') &&
|
||||
item.term !== 'between'
|
||||
"
|
||||
:title="getDynamicStyleLabel(item, item.dynamicField) + ''"
|
||||
>
|
||||
{{ getDynamicStyleLabel(item, item.dynamicField) }}</span
|
||||
>
|
||||
<span
|
||||
v-else-if="
|
||||
!item.term.includes('null') &&
|
||||
!item.term.includes('empty') &&
|
||||
item.term === 'between'
|
||||
"
|
||||
:title="
|
||||
getDynamicStyleLabel(item, item.dynamicMinField) +
|
||||
'≤' +
|
||||
t('chart.drag_block_label_value') +
|
||||
'≤' +
|
||||
getDynamicStyleLabel(item, item.dynamicMaxField)
|
||||
"
|
||||
>
|
||||
{{ getDynamicStyleLabel(item, item.dynamicMinField) }}≤{{
|
||||
t('chart.drag_block_label_value')
|
||||
}}≤{{ getDynamicStyleLabel(item, item.dynamicMaxField) }}
|
||||
</span>
|
||||
<span v-else> </span>
|
||||
</div>
|
||||
<template v-if="chart.type === 'picture-group'">
|
||||
<div title="显示图片" class="pic-group-main">
|
||||
<img
|
||||
@ -688,7 +768,7 @@ init()
|
||||
v-model="state.editTableThresholdDialog"
|
||||
:title="t('chart.threshold')"
|
||||
:visible="state.editTableThresholdDialog"
|
||||
width="800px"
|
||||
width="1050px"
|
||||
class="dialog-css"
|
||||
append-to-body
|
||||
>
|
||||
@ -826,12 +906,21 @@ span {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
flex-wrap: nowrap;
|
||||
|
||||
:nth-child(1) {
|
||||
width: 48px !important;
|
||||
}
|
||||
:nth-child(2) {
|
||||
width: 40px !important;
|
||||
}
|
||||
:nth-child(3) {
|
||||
width: 30px !important;
|
||||
}
|
||||
&:deep(span) {
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
cursor: default;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
@ -868,9 +957,7 @@ span {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
|
||||
background: #f5f6f7;
|
||||
|
||||
&.field-style-dark {
|
||||
background: #1a1a1a;
|
||||
}
|
||||
|
@ -30,7 +30,11 @@ const thresholdCondition = {
|
||||
color: '#ff0000ff',
|
||||
backgroundColor: '#ffffff00',
|
||||
min: '0',
|
||||
max: '1'
|
||||
max: '1',
|
||||
type: 'fixed',
|
||||
dynamicField: { summary: 'value' },
|
||||
dynamicMinField: { summary: 'value' },
|
||||
dynamicMaxField: { summary: 'value' }
|
||||
}
|
||||
const textOptions = [
|
||||
{
|
||||
@ -241,11 +245,108 @@ const addField = item => {
|
||||
item.field = JSON.parse(JSON.stringify(ele))
|
||||
initOptions(item)
|
||||
}
|
||||
if (item.dynamicField?.fieldId === ele.id) {
|
||||
item.dynamicField.field = JSON.parse(JSON.stringify(ele))
|
||||
initOptions(item)
|
||||
}
|
||||
if (item.dynamicMinField?.fieldId === ele.id) {
|
||||
item.dynamicMinField.field = JSON.parse(JSON.stringify(ele))
|
||||
initOptions(item)
|
||||
}
|
||||
if (item.dynamicMaxField?.fieldId === ele.id) {
|
||||
item.dynamicMaxField.field = JSON.parse(JSON.stringify(ele))
|
||||
initOptions(item)
|
||||
}
|
||||
})
|
||||
}
|
||||
changeThreshold()
|
||||
}
|
||||
|
||||
const fieldOptions = [
|
||||
{ label: t('chart.field_fixed'), value: 'fixed' },
|
||||
{ label: t('chart.field_dynamic'), value: 'dynamic' }
|
||||
]
|
||||
const dynamicSummaryOptions = [
|
||||
{
|
||||
id: 'value',
|
||||
name: t('chart.field') + t('chart.drag_block_label_value')
|
||||
},
|
||||
{
|
||||
id: 'avg',
|
||||
name: t('chart.avg') + t('chart.drag_block_label_value')
|
||||
},
|
||||
{
|
||||
id: 'max',
|
||||
name: t('chart.max')
|
||||
},
|
||||
{
|
||||
id: 'min',
|
||||
name: t('chart.min')
|
||||
}
|
||||
]
|
||||
|
||||
const getConditionsFields = (fieldItem, conditionItem, conditionItemField) => {
|
||||
const fieldItemDeType = state.fields.filter(ele => ele.id === fieldItem.fieldId)?.[0]?.deType
|
||||
if (!fieldItemDeType) {
|
||||
fieldItem.fieldId = null
|
||||
conditionItem.fieldId = null
|
||||
conditionItemField.fieldId = null
|
||||
changeThreshold()
|
||||
return state.fields
|
||||
}
|
||||
const result = state.fields.filter(item => item.deType === fieldItemDeType) ?? []
|
||||
if (!result.find(ele => ele.id === conditionItemField.fieldId)) {
|
||||
conditionItemField.fieldId = result[0]?.id
|
||||
addField(conditionItem)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
const getDynamicSummaryOptions = itemId => {
|
||||
const deType = state.fields.filter(ele => ele.id === itemId)?.[0]?.deType
|
||||
if (deType === 1) {
|
||||
// 时间
|
||||
return dynamicSummaryOptions.filter(ele => {
|
||||
return ele.id !== 'avg'
|
||||
})
|
||||
} else if (deType === 0 || deType === 5) {
|
||||
// 文本、地理位置
|
||||
return dynamicSummaryOptions.filter(ele => {
|
||||
return ele.id === 'value'
|
||||
})
|
||||
} else {
|
||||
return dynamicSummaryOptions
|
||||
}
|
||||
}
|
||||
|
||||
const isNotEmptyAndNull = item => {
|
||||
return !item.term.includes('null') && !item.term.includes('empty')
|
||||
}
|
||||
|
||||
const isBetween = item => {
|
||||
return item.term === 'between'
|
||||
}
|
||||
|
||||
const isDynamic = item => {
|
||||
return item.type === 'dynamic'
|
||||
}
|
||||
const changeConditionItemType = item => {
|
||||
if (item.type === 'dynamic') {
|
||||
item.dynamicField.summary = 'value'
|
||||
item.dynamicMinField.summary = 'value'
|
||||
item.dynamicMaxField.summary = 'value'
|
||||
}
|
||||
changeThreshold()
|
||||
}
|
||||
const getFieldOptions = fieldItem => {
|
||||
const deType = state.fields.filter(ele => ele.id === fieldItem.fieldId)?.[0]?.deType
|
||||
if (deType === 1) {
|
||||
return fieldOptions.filter(ele => ele.value === 'fixed')
|
||||
} else {
|
||||
return fieldOptions
|
||||
}
|
||||
}
|
||||
|
||||
init()
|
||||
</script>
|
||||
|
||||
@ -310,9 +411,9 @@ init()
|
||||
v-for="(item, index) in fieldItem.conditions"
|
||||
:key="index"
|
||||
class="line-item"
|
||||
:gutter="10"
|
||||
:gutter="12"
|
||||
>
|
||||
<el-col :span="4">
|
||||
<el-col :span="3">
|
||||
<el-form-item class="form-item">
|
||||
<el-select v-model="item.term" @change="changeThreshold">
|
||||
<el-option-group
|
||||
@ -330,13 +431,27 @@ init()
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="2" v-if="isNotEmptyAndNull(item)" style="padding-left: 0 !important">
|
||||
<el-form-item class="form-item">
|
||||
<el-select
|
||||
v-model="item.type"
|
||||
class="select-item"
|
||||
@change="changeConditionItemType(item)"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-option
|
||||
v-for="opt in getFieldOptions(fieldItem)"
|
||||
:key="opt.value"
|
||||
:label="opt.label"
|
||||
:value="opt.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<!--不是between 不是动态值-->
|
||||
<el-col
|
||||
v-if="
|
||||
!item.term.includes('null') &&
|
||||
!item.term.includes('empty') &&
|
||||
item.term !== 'between'
|
||||
"
|
||||
:span="10"
|
||||
v-if="isNotEmptyAndNull(item) && !isBetween(item) && !isDynamic(item)"
|
||||
:span="12"
|
||||
style="text-align: center"
|
||||
>
|
||||
<el-form-item class="form-item">
|
||||
@ -359,8 +474,72 @@ init()
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col v-if="item.term === 'between'" :span="4" style="text-align: center">
|
||||
<!--不是between 是动态值-->
|
||||
<!--动态值 字段-->
|
||||
<el-col v-if="isNotEmptyAndNull(item) && !isBetween(item) && isDynamic(item)" :span="6">
|
||||
<el-form-item class="form-item">
|
||||
<el-select
|
||||
v-model="item.dynamicField.fieldId"
|
||||
@change="addField(item)"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-option
|
||||
class="series-select-option"
|
||||
v-for="itemFieldOption in getConditionsFields(
|
||||
fieldItem,
|
||||
item,
|
||||
item.dynamicField
|
||||
)"
|
||||
:key="itemFieldOption.id"
|
||||
:label="itemFieldOption.name"
|
||||
:value="itemFieldOption.id"
|
||||
:disabled="chart.type === 'table-info' && itemFieldOption.deType === 7"
|
||||
>
|
||||
<el-icon style="margin-right: 8px">
|
||||
<Icon
|
||||
><component
|
||||
:class="`field-icon-${
|
||||
fieldType[[2, 3].includes(itemFieldOption.deType) ? 2 : 0]
|
||||
}`"
|
||||
class="svg-icon"
|
||||
:is="iconFieldMap[fieldType[itemFieldOption.deType]]"
|
||||
></component
|
||||
></Icon>
|
||||
</el-icon>
|
||||
{{ itemFieldOption.name }}
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<!--动态值聚合方式-->
|
||||
<el-col
|
||||
v-if="isNotEmptyAndNull(item) && !isBetween(item) && isDynamic(item)"
|
||||
:span="6"
|
||||
style="text-align: center"
|
||||
>
|
||||
<el-form-item class="form-item">
|
||||
<el-select
|
||||
:placeholder="t('chart.aggregation')"
|
||||
v-model="item.dynamicField.summary"
|
||||
@change="changeThreshold"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-option
|
||||
v-for="opt in getDynamicSummaryOptions(item.dynamicField.fieldId)"
|
||||
:key="opt.id"
|
||||
:label="opt.name"
|
||||
:value="opt.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<!--是between 不是动态值-->
|
||||
<!--between 开始值-->
|
||||
<el-col
|
||||
v-if="isNotEmptyAndNull(item) && isBetween(item) && !isDynamic(item)"
|
||||
:span="5"
|
||||
style="text-align: center"
|
||||
>
|
||||
<el-form-item class="form-item">
|
||||
<el-input-number
|
||||
v-model="item.min"
|
||||
@ -372,14 +551,21 @@ init()
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col v-if="item.term === 'between'" :span="2" style="text-align: center">
|
||||
<span style="margin: 0 4px">
|
||||
≤ {{ t('chart.drag_block_label_value') }} ≤
|
||||
<el-col
|
||||
v-if="isBetween(item) && !isDynamic(item)"
|
||||
:span="2"
|
||||
style="margin-top: 4px; text-align: center"
|
||||
>
|
||||
<span style="margin: 0 -5px">
|
||||
≤ {{ t('chart.drag_block_label_value') }} ≤
|
||||
</span>
|
||||
</el-col>
|
||||
|
||||
<el-col v-if="item.term === 'between'" :span="4" style="text-align: center">
|
||||
<!--between 结束值-->
|
||||
<el-col
|
||||
v-if="isNotEmptyAndNull(item) && isBetween(item) && !isDynamic(item)"
|
||||
:span="5"
|
||||
style="text-align: center"
|
||||
>
|
||||
<el-form-item class="form-item">
|
||||
<el-input-number
|
||||
v-model="item.max"
|
||||
@ -392,11 +578,127 @@ init()
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<div
|
||||
style="display: flex; align-items: center; justify-content: center; margin-left: 8px"
|
||||
<!--是between 动态值-->
|
||||
<!--开始值 动态值字段-->
|
||||
<el-col
|
||||
v-if="isNotEmptyAndNull(item) && isBetween(item) && isDynamic(item)"
|
||||
class="minField"
|
||||
:span="3"
|
||||
>
|
||||
<div class="color-title">{{ t('chart.textColor') }}</div>
|
||||
<el-form-item class="form-item">
|
||||
<el-select v-model="item.dynamicMinField.fieldId" @change="addField(item)">
|
||||
<el-option
|
||||
class="series-select-option"
|
||||
v-for="itemFieldOption in getConditionsFields(
|
||||
fieldItem,
|
||||
item,
|
||||
item.dynamicMinField
|
||||
)"
|
||||
:key="itemFieldOption.id"
|
||||
:label="itemFieldOption.name"
|
||||
:value="itemFieldOption.id"
|
||||
:disabled="chart.type === 'table-info' && itemFieldOption.deType === 7"
|
||||
>
|
||||
<el-icon style="margin-right: 8px">
|
||||
<Icon
|
||||
><component
|
||||
:class="`field-icon-${
|
||||
fieldType[[2, 3].includes(itemFieldOption.deType) ? 2 : 0]
|
||||
}`"
|
||||
class="svg-icon"
|
||||
:is="iconFieldMap[fieldType[itemFieldOption.deType]]"
|
||||
></component
|
||||
></Icon>
|
||||
</el-icon>
|
||||
{{ itemFieldOption.name }}
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<!--开始值 动态值聚合方式-->
|
||||
<el-col
|
||||
v-if="isNotEmptyAndNull(item) && isBetween(item) && isDynamic(item)"
|
||||
class="minValue"
|
||||
:span="2"
|
||||
style="padding-left: 0 !important"
|
||||
>
|
||||
<el-form-item class="form-item">
|
||||
<el-select v-model="item.dynamicMinField.summary" @change="changeThreshold">
|
||||
<el-option
|
||||
v-for="opt in getDynamicSummaryOptions(item.dynamicMinField.fieldId)"
|
||||
:key="opt.id"
|
||||
:label="opt.name"
|
||||
:value="opt.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col
|
||||
v-if="isBetween(item) && isDynamic(item)"
|
||||
class="term"
|
||||
:span="2"
|
||||
style="margin-top: 4px; text-align: center"
|
||||
>
|
||||
<span style="margin: 0 -5px">
|
||||
≤ {{ t('chart.drag_block_label_value') }} ≤
|
||||
</span>
|
||||
</el-col>
|
||||
<!--结束值 动态值字段-->
|
||||
<el-col
|
||||
v-if="isNotEmptyAndNull(item) && isBetween(item) && isDynamic(item)"
|
||||
class="maxField"
|
||||
:span="3"
|
||||
>
|
||||
<el-form-item class="form-item">
|
||||
<el-select v-model="item.dynamicMaxField.fieldId" @change="addField(item)">
|
||||
<el-option
|
||||
class="series-select-option"
|
||||
v-for="itemFieldOption in getConditionsFields(
|
||||
fieldItem,
|
||||
item,
|
||||
item.dynamicMaxField
|
||||
)"
|
||||
:key="itemFieldOption.id"
|
||||
:label="itemFieldOption.name"
|
||||
:value="itemFieldOption.id"
|
||||
:disabled="chart.type === 'table-info' && itemFieldOption.deType === 7"
|
||||
>
|
||||
<el-icon style="margin-right: 8px">
|
||||
<Icon
|
||||
><component
|
||||
:class="`field-icon-${
|
||||
fieldType[[2, 3].includes(itemFieldOption.deType) ? 2 : 0]
|
||||
}`"
|
||||
class="svg-icon"
|
||||
:is="iconFieldMap[fieldType[itemFieldOption.deType]]"
|
||||
></component
|
||||
></Icon>
|
||||
</el-icon>
|
||||
{{ itemFieldOption.name }}
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<!--结束值 动态值聚合方式-->
|
||||
<el-col
|
||||
v-if="isNotEmptyAndNull(item) && isBetween(item) && isDynamic(item)"
|
||||
class="maxValue"
|
||||
:span="2"
|
||||
style="padding-left: 0 !important"
|
||||
>
|
||||
<el-form-item class="form-item">
|
||||
<el-select v-model="item.dynamicMaxField.summary" @change="changeThreshold">
|
||||
<el-option
|
||||
v-for="opt in getDynamicSummaryOptions(item.dynamicMaxField.fieldId)"
|
||||
:key="opt.id"
|
||||
:label="opt.name"
|
||||
:value="opt.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="3">
|
||||
<el-form-item class="form-item" :label="t('chart.textColor')">
|
||||
<el-color-picker
|
||||
is-custom
|
||||
size="large"
|
||||
@ -407,12 +709,9 @@ init()
|
||||
@change="changeThreshold"
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div
|
||||
style="display: flex; align-items: center; justify-content: center; margin-left: 8px"
|
||||
>
|
||||
<div class="color-title">{{ t('chart.backgroundColor') }}</div>
|
||||
<el-form-item class="form-item">
|
||||
</el-col>
|
||||
<el-col :span="3">
|
||||
<el-form-item class="form-item" :label="t('chart.backgroundColor')">
|
||||
<el-color-picker
|
||||
is-custom
|
||||
size="large"
|
||||
@ -423,22 +722,22 @@ init()
|
||||
@change="changeThreshold"
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div
|
||||
style="display: flex; align-items: center; justify-content: center; margin-left: 8px"
|
||||
>
|
||||
<el-button
|
||||
class="circle-button m-icon-btn"
|
||||
text
|
||||
@click="removeCondition(fieldItem, index)"
|
||||
>
|
||||
<el-icon size="20px" style="color: #646a73">
|
||||
<Icon name="icon_delete-trash_outlined"
|
||||
><icon_deleteTrash_outlined class="svg-icon"
|
||||
/></Icon>
|
||||
</el-icon>
|
||||
</el-button>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="1">
|
||||
<div style="display: flex; align-items: center; justify-content: center">
|
||||
<el-button
|
||||
class="circle-button m-icon-btn"
|
||||
text
|
||||
@click="removeCondition(fieldItem, index)"
|
||||
>
|
||||
<el-icon size="20px" style="color: #646a73">
|
||||
<Icon name="icon_delete-trash_outlined"
|
||||
><icon_deleteTrash_outlined class="svg-icon"
|
||||
/></Icon>
|
||||
</el-icon>
|
||||
</el-button>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-row>
|
||||
|
||||
|
@ -1074,7 +1074,19 @@ const onAssistLineChange = val => {
|
||||
|
||||
const onThresholdChange = val => {
|
||||
view.value.senior.threshold = val
|
||||
renderChart(view.value)
|
||||
let type = undefined
|
||||
view.value.senior.threshold?.tableThreshold?.some(item => {
|
||||
if (item.conditions.some(i => i.type === 'dynamic')) {
|
||||
type = 'calcData'
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
if (type) {
|
||||
calcData(view.value)
|
||||
} else {
|
||||
renderChart(view.value)
|
||||
}
|
||||
}
|
||||
|
||||
const onMapMappingChange = val => {
|
||||
@ -1766,9 +1778,7 @@ const deleteChartFieldItem = id => {
|
||||
</div>
|
||||
<el-popover show-arrow :offset="8" placement="bottom" width="200" trigger="click">
|
||||
<template #reference>
|
||||
<el-icon
|
||||
v-show="route.path !== '/dvCanvas'"
|
||||
style="margin-left: 4px; cursor: pointer"
|
||||
<el-icon style="margin-left: 4px; cursor: pointer"
|
||||
><Icon><dvInfoSvg class="svg-icon" /></Icon
|
||||
></el-icon>
|
||||
</template>
|
||||
|
@ -1,4 +1,12 @@
|
||||
import { S2Event, S2Options, TableColCell, TableDataCell, TableSheet, ViewMeta } from '@antv/s2'
|
||||
import {
|
||||
type LayoutResult,
|
||||
S2Event,
|
||||
S2Options,
|
||||
TableColCell,
|
||||
TableDataCell,
|
||||
TableSheet,
|
||||
ViewMeta
|
||||
} from '@antv/s2'
|
||||
import { formatterItem, valueFormatter } from '../../../formatter'
|
||||
import { parseJson } from '../../../util'
|
||||
import { S2ChartView, S2DrawOptions } from '../../types/impl/s2'
|
||||
@ -192,6 +200,60 @@ export class TableInfo extends S2ChartView<TableSheet> {
|
||||
// 开始渲染
|
||||
const newChart = new TableSheet(containerDom, s2DataConfig, s2Options)
|
||||
|
||||
// 自适应铺满
|
||||
if (customAttr.basicStyle.tableColumnMode === 'adapt') {
|
||||
newChart.on(S2Event.LAYOUT_RESIZE_COL_WIDTH, () => {
|
||||
newChart.store.set('lastLayoutResult', newChart.facet.layoutResult)
|
||||
})
|
||||
newChart.on(S2Event.LAYOUT_AFTER_HEADER_LAYOUT, (ev: LayoutResult) => {
|
||||
const status = newChart.store.get('status')
|
||||
if (status === 'default') {
|
||||
return
|
||||
}
|
||||
const lastLayoutResult = newChart.store.get('lastLayoutResult') as LayoutResult
|
||||
if (status === 'expanded' && lastLayoutResult) {
|
||||
// 拖拽表头定义宽度,和上一次布局对比,保留除已拖拽列之外的宽度
|
||||
const widthByFieldValue = newChart.options.style?.colCfg?.widthByFieldValue
|
||||
const lastLayoutWidthMap: Record<string, number> = lastLayoutResult?.colLeafNodes.reduce(
|
||||
(p, n) => {
|
||||
p[n.value] = widthByFieldValue?.[n.value] ?? n.width
|
||||
return p
|
||||
},
|
||||
{}
|
||||
)
|
||||
const totalWidth = ev.colLeafNodes.reduce((p, n) => {
|
||||
n.width = lastLayoutWidthMap[n.value]
|
||||
n.x = p
|
||||
return p + n.width
|
||||
}, 0)
|
||||
ev.colsHierarchy.width = totalWidth
|
||||
} else {
|
||||
// 第一次渲染初始化,把图片字段固定为 120 进行计算
|
||||
const urlFields = fields.filter(field => field.deType === 7).map(f => f.dataeaseName)
|
||||
const totalWidthWithImg = ev.colLeafNodes.reduce((p, n) => {
|
||||
return p + (urlFields.includes(n.field) ? 120 : n.width)
|
||||
}, 0)
|
||||
if (containerDom.offsetWidth <= totalWidthWithImg) {
|
||||
// 图库计算的布局宽度已经大于等于容器宽度,不需要再扩大,不处理
|
||||
newChart.store.set('status', 'default')
|
||||
return
|
||||
}
|
||||
// 图片字段固定 120, 剩余宽度按比例均摊到其他字段进行扩大
|
||||
const totalWidthWithoutImg = ev.colLeafNodes.reduce((p, n) => {
|
||||
return p + (urlFields.includes(n.field) ? 0 : n.width)
|
||||
}, 0)
|
||||
const restWidth = containerDom.offsetWidth - urlFields.length * 120
|
||||
const scale = restWidth / totalWidthWithoutImg
|
||||
const totalWidth = ev.colLeafNodes.reduce((p, n) => {
|
||||
n.width = urlFields.includes(n.field) ? 120 : n.width * scale
|
||||
n.x = p
|
||||
return p + n.width
|
||||
}, 0)
|
||||
ev.colsHierarchy.width = Math.min(containerDom.offsetWidth, totalWidth)
|
||||
newChart.store.set('status', 'expanded')
|
||||
}
|
||||
})
|
||||
}
|
||||
// click
|
||||
newChart.on(S2Event.DATA_CELL_CLICK, ev => {
|
||||
const cell = newChart.getCell(ev.target)
|
||||
|
@ -4,6 +4,7 @@ import { copyContent, SortTooltip } from '@/views/chart/components/js/panel/comm
|
||||
import { S2ChartView, S2DrawOptions } from '@/views/chart/components/js/panel/types/impl/s2'
|
||||
import { parseJson } from '@/views/chart/components/js/util'
|
||||
import {
|
||||
type LayoutResult,
|
||||
S2Event,
|
||||
S2Options,
|
||||
SHAPE_STYLE_MAP,
|
||||
@ -207,7 +208,50 @@ export class TableNormal extends S2ChartView<TableSheet> {
|
||||
}
|
||||
// 开始渲染
|
||||
const newChart = new TableSheet(containerDom, s2DataConfig, s2Options)
|
||||
|
||||
// 自适应铺满
|
||||
if (customAttr.basicStyle.tableColumnMode === 'adapt') {
|
||||
newChart.on(S2Event.LAYOUT_RESIZE_COL_WIDTH, () => {
|
||||
newChart.store.set('lastLayoutResult', newChart.facet.layoutResult)
|
||||
})
|
||||
newChart.on(S2Event.LAYOUT_AFTER_HEADER_LAYOUT, (ev: LayoutResult) => {
|
||||
const status = newChart.store.get('status')
|
||||
if (status === 'default') {
|
||||
return
|
||||
}
|
||||
const lastLayoutResult = newChart.store.get('lastLayoutResult') as LayoutResult
|
||||
if (status === 'expanded' && lastLayoutResult) {
|
||||
// 拖拽表头定义宽度,和上一次布局对比,保留除已拖拽列之外的宽度
|
||||
const widthByFieldValue = newChart.options.style?.colCfg?.widthByFieldValue
|
||||
const lastLayoutWidthMap: Record<string, number> = lastLayoutResult?.colLeafNodes.reduce(
|
||||
(p, n) => {
|
||||
p[n.value] = widthByFieldValue?.[n.value] ?? n.width
|
||||
return p
|
||||
},
|
||||
{}
|
||||
)
|
||||
const totalWidth = ev.colLeafNodes.reduce((p, n) => {
|
||||
n.width = lastLayoutWidthMap[n.value]
|
||||
n.x = p
|
||||
return p + n.width
|
||||
}, 0)
|
||||
ev.colsHierarchy.width = totalWidth
|
||||
} else {
|
||||
const scale = containerDom.offsetWidth / ev.colsHierarchy.width
|
||||
if (scale <= 1) {
|
||||
// 图库计算的布局宽度已经大于等于容器宽度,不需要再扩大,不处理
|
||||
newChart.store.set('status', 'default')
|
||||
return
|
||||
}
|
||||
const totalWidth = ev.colLeafNodes.reduce((p, n) => {
|
||||
n.width = n.width * scale
|
||||
n.x = p
|
||||
return p + n.width
|
||||
}, 0)
|
||||
ev.colsHierarchy.width = Math.min(containerDom.offsetWidth, totalWidth)
|
||||
newChart.store.set('status', 'expanded')
|
||||
}
|
||||
})
|
||||
}
|
||||
// click
|
||||
newChart.on(S2Event.DATA_CELL_CLICK, ev => {
|
||||
const cell = newChart.getCell(ev.target)
|
||||
|
@ -412,7 +412,6 @@ export function getStyle(chart: Chart): Style {
|
||||
}
|
||||
switch (basicStyle.tableColumnMode) {
|
||||
case 'adapt': {
|
||||
delete style.cellCfg.width
|
||||
style.layoutWidthType = 'compact'
|
||||
break
|
||||
}
|
||||
@ -520,6 +519,7 @@ export function getConditions(chart: Chart) {
|
||||
const headerValueBgColor = isAlphaColor(tableHeader.tableHeaderBgColor)
|
||||
? tableHeader.tableHeaderBgColor
|
||||
: hexColorToRGBA(tableHeader.tableHeaderBgColor, basicStyle.alpha)
|
||||
const filedValueMap = getFieldValueMap(chart)
|
||||
for (let i = 0; i < conditions.length; i++) {
|
||||
const field = conditions[i]
|
||||
let defaultValueColor = valueColor
|
||||
@ -541,7 +541,7 @@ export function getConditions(chart: Chart) {
|
||||
return null
|
||||
}
|
||||
return {
|
||||
fill: mappingColor(value, defaultValueColor, field, 'color')
|
||||
fill: mappingColor(value, defaultValueColor, field, 'color', filedValueMap, rowData)
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -554,7 +554,14 @@ export function getConditions(chart: Chart) {
|
||||
if (rowData?.id && rowData?.field === rowData.id) {
|
||||
return null
|
||||
}
|
||||
const fill = mappingColor(value, defaultBgColor, field, 'backgroundColor')
|
||||
const fill = mappingColor(
|
||||
value,
|
||||
defaultBgColor,
|
||||
field,
|
||||
'backgroundColor',
|
||||
filedValueMap,
|
||||
rowData
|
||||
)
|
||||
if (isTransparent(fill)) {
|
||||
return null
|
||||
}
|
||||
@ -566,13 +573,28 @@ export function getConditions(chart: Chart) {
|
||||
return res
|
||||
}
|
||||
|
||||
export function mappingColor(value, defaultColor, field, type) {
|
||||
export function mappingColor(value, defaultColor, field, type, filedValueMap, rowData) {
|
||||
let color
|
||||
for (let i = 0; i < field.conditions.length; i++) {
|
||||
let flag = false
|
||||
const t = field.conditions[i]
|
||||
if (field.field.deType === 2 || field.field.deType === 3 || field.field.deType === 4) {
|
||||
const tv = parseFloat(t.value)
|
||||
let tv, max, min
|
||||
if (t.type === 'dynamic') {
|
||||
if (t.term === 'between') {
|
||||
max = parseFloat(getValue(t.dynamicMaxField, filedValueMap, rowData))
|
||||
min = parseFloat(getValue(t.dynamicMinField, filedValueMap, rowData))
|
||||
} else {
|
||||
tv = parseFloat(getValue(t.dynamicField, filedValueMap, rowData))
|
||||
}
|
||||
} else {
|
||||
if (t.term === 'between') {
|
||||
min = parseFloat(t.min)
|
||||
max = parseFloat(t.max)
|
||||
} else {
|
||||
tv = parseFloat(t.value)
|
||||
}
|
||||
}
|
||||
if (t.term === 'eq') {
|
||||
if (value === tv) {
|
||||
color = t[type]
|
||||
@ -604,8 +626,6 @@ export function mappingColor(value, defaultColor, field, type) {
|
||||
flag = true
|
||||
}
|
||||
} else if (t.term === 'between') {
|
||||
const min = parseFloat(t.min)
|
||||
const max = parseFloat(t.max)
|
||||
if (min <= value && value <= max) {
|
||||
color = t[type]
|
||||
flag = true
|
||||
@ -708,6 +728,24 @@ export function mappingColor(value, defaultColor, field, type) {
|
||||
return color
|
||||
}
|
||||
|
||||
function getFieldValueMap(view) {
|
||||
const fieldValueMap = {}
|
||||
if (view.data && view.data.dynamicAssistLines && view.data.dynamicAssistLines.length > 0) {
|
||||
view.data.dynamicAssistLines.forEach(ele => {
|
||||
fieldValueMap[ele.summary + '-' + ele.fieldId] = ele.value
|
||||
})
|
||||
}
|
||||
return fieldValueMap
|
||||
}
|
||||
|
||||
function getValue(field, filedValueMap, rowData) {
|
||||
if (field.summary === 'value') {
|
||||
return rowData ? rowData[field.field?.dataeaseName] : undefined
|
||||
} else {
|
||||
return filedValueMap[field.summary + '-' + field.fieldId]
|
||||
}
|
||||
}
|
||||
|
||||
export function handleTableEmptyStrategy(chart: Chart) {
|
||||
let newData = (chart.data?.tableRow || []) as Record<string, any>[]
|
||||
let intersectionArr = []
|
||||
|
@ -172,11 +172,11 @@ const renderChart = (viewInfo: Chart, resetPageInfo: boolean) => {
|
||||
recursionTransObj(customAttrTrans, actualChart.customAttr, scale.value, terminal.value)
|
||||
recursionTransObj(customStyleTrans, actualChart.customStyle, scale.value, terminal.value)
|
||||
|
||||
setupPage(actualChart, resetPageInfo)
|
||||
myChart?.facet?.timer?.stop()
|
||||
myChart?.facet?.cancelScrollFrame()
|
||||
myChart?.destroy()
|
||||
myChart = null
|
||||
setupPage(actualChart, resetPageInfo)
|
||||
const chartView = chartViewManager.getChartView(
|
||||
viewInfo.render,
|
||||
viewInfo.type
|
||||
|
@ -260,6 +260,8 @@ const afterTreeInit = () => {
|
||||
})
|
||||
}
|
||||
|
||||
const copyLoading = ref(false)
|
||||
|
||||
const emit = defineEmits(['nodeClick'])
|
||||
|
||||
const operation = (cmd: string, data: BusiTreeNode, nodeType: string) => {
|
||||
@ -291,29 +293,36 @@ const operation = (cmd: string, data: BusiTreeNode, nodeType: string) => {
|
||||
id: data.id,
|
||||
pid: targetPid || '0'
|
||||
}
|
||||
copyResource(params).then(data => {
|
||||
const baseUrl =
|
||||
curCanvasType.value === 'dataV'
|
||||
? `#/dvCanvas?opt=copy&pid=${params.pid}&dvId=${data.data}`
|
||||
: `#/dashboard?opt=copy&pid=${params.pid}&resourceId=${data.data}`
|
||||
if (isEmbedded.value) {
|
||||
embeddedStore.clearState()
|
||||
embeddedStore.setPid(params.pid as string)
|
||||
embeddedStore.setOpt('copy')
|
||||
if (curCanvasType.value === 'dataV') {
|
||||
embeddedStore.setDvId(data.data)
|
||||
} else {
|
||||
embeddedStore.setResourceId(data.data)
|
||||
|
||||
copyLoading.value = true
|
||||
|
||||
copyResource(params)
|
||||
.then(data => {
|
||||
const baseUrl =
|
||||
curCanvasType.value === 'dataV'
|
||||
? `#/dvCanvas?opt=copy&pid=${params.pid}&dvId=${data.data}`
|
||||
: `#/dashboard?opt=copy&pid=${params.pid}&resourceId=${data.data}`
|
||||
if (isEmbedded.value) {
|
||||
embeddedStore.clearState()
|
||||
embeddedStore.setPid(params.pid as string)
|
||||
embeddedStore.setOpt('copy')
|
||||
if (curCanvasType.value === 'dataV') {
|
||||
embeddedStore.setDvId(data.data)
|
||||
} else {
|
||||
embeddedStore.setResourceId(data.data)
|
||||
}
|
||||
useEmitt().emitter.emit(
|
||||
'changeCurrentComponent',
|
||||
curCanvasType.value === 'dataV' ? 'VisualizationEditor' : 'DashboardEditor'
|
||||
)
|
||||
return
|
||||
}
|
||||
useEmitt().emitter.emit(
|
||||
'changeCurrentComponent',
|
||||
curCanvasType.value === 'dataV' ? 'VisualizationEditor' : 'DashboardEditor'
|
||||
)
|
||||
return
|
||||
}
|
||||
const newWindow = window.open(baseUrl, '_blank')
|
||||
initOpenHandler(newWindow)
|
||||
})
|
||||
const newWindow = window.open(baseUrl, '_blank')
|
||||
initOpenHandler(newWindow)
|
||||
})
|
||||
.finally(() => {
|
||||
copyLoading.value = false
|
||||
})
|
||||
} else {
|
||||
resourceGroupOpt.value.optInit(nodeType, data, cmd, ['copy'].includes(cmd))
|
||||
}
|
||||
@ -593,7 +602,7 @@ defineExpose({
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
<el-scrollbar class="custom-tree">
|
||||
<el-scrollbar class="custom-tree" v-loading="copyLoading">
|
||||
<el-tree
|
||||
menu
|
||||
ref="resourceListTree"
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="info-card">
|
||||
<div v-if="dvInfo.type === 'dashboard'" class="info-title">仪表板ID</div>
|
||||
<div v-if="dvInfo.type === 'dashboard'" class="info-content">{{ dvInfo.id }}</div>
|
||||
<div class="info-title">图表ID</div>
|
||||
<div class="info-content">{{ dvInfo.id }}</div>
|
||||
<div v-if="dvInfo.creatorName" class="info-title">{{ t('visualization.create_by') }}</div>
|
||||
<div v-if="dvInfo.creatorName" class="info-content">{{ dvInfo.creatorName }}</div>
|
||||
<div class="info-title">{{ t('visualization.create_time') }}</div>
|
||||
|
@ -928,7 +928,7 @@ defineExpose({
|
||||
</div>
|
||||
</template>
|
||||
<template v-if="notapiexcelconfig">
|
||||
<el-form-item label="连接方式" prop="type">
|
||||
<el-form-item label="连接方式" prop="type" v-if="form.type !== 'es'">
|
||||
<el-radio-group v-model="form.configuration.urlType">
|
||||
<el-radio label="hostName">主机名</el-radio>
|
||||
<el-radio label="jdbcUrl">JDBC 连接</el-radio>
|
||||
@ -950,7 +950,7 @@ defineExpose({
|
||||
<el-form-item
|
||||
:label="t('datasource.host')"
|
||||
prop="configuration.host"
|
||||
v-if="form.configuration.urlType !== 'jdbcUrl'"
|
||||
v-if="form.configuration.urlType !== 'jdbcUrl' && form.type !== 'es'"
|
||||
>
|
||||
<el-input
|
||||
v-model="form.configuration.host"
|
||||
@ -961,7 +961,7 @@ defineExpose({
|
||||
<el-form-item
|
||||
:label="t('datasource.port')"
|
||||
prop="configuration.port"
|
||||
v-if="form.configuration.urlType !== 'jdbcUrl'"
|
||||
v-if="form.configuration.urlType !== 'jdbcUrl' && form.type !== 'es'"
|
||||
>
|
||||
<el-input-number
|
||||
v-model="form.configuration.port"
|
||||
@ -977,7 +977,7 @@ defineExpose({
|
||||
<el-form-item
|
||||
:label="t('datasource.data_base')"
|
||||
prop="configuration.dataBase"
|
||||
v-if="form.configuration.urlType !== 'jdbcUrl'"
|
||||
v-if="form.configuration.urlType !== 'jdbcUrl' && form.type !== 'es'"
|
||||
>
|
||||
<el-input
|
||||
v-model="form.configuration.dataBase"
|
||||
@ -1029,6 +1029,17 @@ defineExpose({
|
||||
{{ t('datasource.kerbers_info') }}
|
||||
</p>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="form.type == 'es'"
|
||||
:label="$t('datasource.datasource_url')"
|
||||
prop="configuration.url"
|
||||
>
|
||||
<el-input
|
||||
v-model="form.configuration.url"
|
||||
:placeholder="$t('datasource.please_input_datasource_url')"
|
||||
autocomplete="off"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('datasource.user_name')" v-if="form.type !== 'presto'">
|
||||
<el-input
|
||||
:placeholder="t('common.inputText') + t('datasource.user_name')"
|
||||
@ -1083,7 +1094,7 @@ defineExpose({
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
:label="t('datasource.extra_params')"
|
||||
v-if="form.configuration.urlType !== 'jdbcUrl'"
|
||||
v-if="form.configuration.urlType !== 'jdbcUrl' && form.type !== 'es'"
|
||||
>
|
||||
<el-input
|
||||
:placeholder="t('common.inputText') + t('datasource.extra_params')"
|
||||
|
@ -42,6 +42,12 @@ export const dsTypes = [
|
||||
extraParams:
|
||||
'characterEncoding=UTF-8&connectTimeout=5000&useSSL=false&allowPublicKeyRetrieval=true'
|
||||
},
|
||||
{
|
||||
type: 'es',
|
||||
name: 'Elasticsearch',
|
||||
catalog: 'OLAP',
|
||||
extraParams: ''
|
||||
},
|
||||
{
|
||||
type: 'StarRocks',
|
||||
name: 'StarRocks',
|
||||
|
@ -142,7 +142,7 @@ const nickName = ref('')
|
||||
const dsName = ref('')
|
||||
const userDrawer = ref(false)
|
||||
const rawDatasourceList = ref([])
|
||||
const showPriority = ref(true)
|
||||
const showPriority = ref(false)
|
||||
const showSSH = ref(true)
|
||||
const datasourceEditor = ref()
|
||||
const activeTab = ref('')
|
||||
@ -378,6 +378,7 @@ const initSearch = () => {
|
||||
state.filterTable = tableData.value.filter(ele =>
|
||||
ele.tableName.toLowerCase().includes(nickName.value.toLowerCase())
|
||||
)
|
||||
console.log(tableData.value)
|
||||
state.paginationConfig.total = state.filterTable.length
|
||||
}
|
||||
|
||||
@ -862,6 +863,7 @@ const operation = (cmd: string, data: Tree, nodeType: string) => {
|
||||
}
|
||||
|
||||
const handleClick = (tabName: TabPaneName) => {
|
||||
console.log(tabName)
|
||||
switch (tabName) {
|
||||
case 'config':
|
||||
listDatasourceTables({ datasourceId: nodeInfo.id }).then(res => {
|
||||
@ -1372,7 +1374,7 @@ const getMenuList = (val: boolean) => {
|
||||
}}</BaseInfoItem>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<template v-if="!['Excel', 'API'].includes(nodeInfo.type)">
|
||||
<template v-if="!['Excel', 'API', 'es'].includes(nodeInfo.type)">
|
||||
<el-row :gutter="24" v-show="nodeInfo.configuration.urlType !== 'jdbcUrl'">
|
||||
<el-col :span="12">
|
||||
<BaseInfoItem :label="t('datasource.host')">{{
|
||||
@ -1499,6 +1501,15 @@ const getMenuList = (val: boolean) => {
|
||||
</el-row>
|
||||
</template>
|
||||
</template>
|
||||
<template v-if="['es'].includes(nodeInfo.type)">
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="12">
|
||||
<BaseInfoItem :label="t('datasource.datasource_url')">{{
|
||||
nodeInfo.configuration.url
|
||||
}}</BaseInfoItem>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</template>
|
||||
</template>
|
||||
</BaseInfoContent>
|
||||
<BaseInfoContent
|
||||
|
2
de-xpack
@ -1 +1 @@
|
||||
Subproject commit ea86c71bc9060fee727ecc138e30ad8b0ae1bf84
|
||||
Subproject commit d415457510f49faf552ad2bfe51030f8c228e736
|
@ -21,6 +21,9 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
public class ProviderFactory {
|
||||
|
||||
public static Provider getProvider(String type) throws DEException {
|
||||
if (type.equalsIgnoreCase("es")) {
|
||||
return SpringContextUtil.getApplicationContext().getBean("esProvider", Provider.class);
|
||||
}
|
||||
List<String> list = Arrays.stream(DatasourceConfiguration.DatasourceType.values()).map(DatasourceConfiguration.DatasourceType::getType).toList();
|
||||
if (list.contains(type)) {
|
||||
return SpringContextUtil.getApplicationContext().getBean("calciteProvider", Provider.class);
|
||||
|
@ -18,6 +18,7 @@ public class DatasourceConfiguration extends Configuration {
|
||||
impala("impala", "Apache Impala", "OLAP", "`", "`"),
|
||||
mariadb("mariadb", "Mariadb", "OLTP", "`", "`"),
|
||||
StarRocks("StarRocks", "StarRocks", "OLAP", "`", "`"),
|
||||
es("es", "Elasticsearch", "OLAP", "\"", "\""),
|
||||
doris("doris", "Apache Doris", "OLAP", "`", "`"),
|
||||
TiDB("TiDB", "TiDB", "OLTP", "`", "`"),
|
||||
oracle("oracle", "ORACLE", "OLTP", "\"", "\""),
|
||||
|
@ -0,0 +1,19 @@
|
||||
package io.dataease.extensions.view.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@Data
|
||||
public class ChartSeniorThresholdCfgDTO {
|
||||
/**
|
||||
* 是否启用
|
||||
*/
|
||||
private boolean enable;
|
||||
|
||||
/**
|
||||
* 表格阈值
|
||||
*/
|
||||
private List<TableThresholdDTO> tableThreshold;
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package io.dataease.extensions.view.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author jianneng
|
||||
* @date 2024/9/19 18:34
|
||||
**/
|
||||
@Data
|
||||
public class ChartSeniorThresholdDTO {
|
||||
/**
|
||||
* 对比方式
|
||||
*/
|
||||
private String term;
|
||||
/**
|
||||
* 类型,固定值、动态值
|
||||
*/
|
||||
private String type;
|
||||
/**
|
||||
* 动态值字段
|
||||
*/
|
||||
private ThresholdDynamicFieldDTO dynamicField;
|
||||
/**
|
||||
* 动态值最小值字段 仅当term为between时使用
|
||||
*/
|
||||
private ThresholdDynamicFieldDTO dynamicMinField;
|
||||
/**
|
||||
* 动态值最大值字段 仅当term为between时使用
|
||||
*/
|
||||
private ThresholdDynamicFieldDTO dynamicMaxField;
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package io.dataease.extensions.view.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author jianneng
|
||||
* @date 2024/9/19 18:31
|
||||
**/
|
||||
@Data
|
||||
public class TableThresholdDTO {
|
||||
/**
|
||||
* 字段id
|
||||
*/
|
||||
private String fieldId;
|
||||
/**
|
||||
* 字段
|
||||
*/
|
||||
private ChartViewFieldDTO field;
|
||||
/**
|
||||
* 条件
|
||||
*/
|
||||
private List<ChartSeniorThresholdDTO> conditions;
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package io.dataease.extensions.view.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author jianneng
|
||||
* @date 2024/9/19 18:31
|
||||
**/
|
||||
@Data
|
||||
public class ThresholdDynamicFieldDTO {
|
||||
/**
|
||||
* 字段id
|
||||
*/
|
||||
private String fieldId;
|
||||
/**
|
||||
* 字段
|
||||
*/
|
||||
private ChartViewFieldDTO field;
|
||||
/**
|
||||
* 条件
|
||||
*/
|
||||
private String summary;
|
||||
}
|