Merge branch 'dev-v2' into pr@dev-v2@fixDS

This commit is contained in:
taojinlong 2024-08-23 09:48:18 +08:00 committed by GitHub
commit e95f1c7fee
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
66 changed files with 2352 additions and 260 deletions

View File

@ -25,7 +25,7 @@ public class MybatisPlusGenerator {
/**
* 这是要生成代码的表名称
*/
private static final String TABLE_NAME = "visualization_report_filter";
private static final String TABLE_NAME = "visualization_outer_params_target_view_info";
/**
* 下面两个配置基本上不用动

View File

@ -10,6 +10,7 @@ import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@Component
public class IndicatorHandler extends YoyChartHandler {
@ -36,23 +37,19 @@ public class IndicatorHandler extends YoyChartHandler {
var xAxis = formatResult.getAxisMap().get(ChartAxis.xAxis);
var yAxis = formatResult.getAxisMap().get(ChartAxis.yAxis);
var allFields = (List<ChartViewFieldDTO>) filterResult.getContext().get("allFields");
ChartViewFieldDTO chartViewFieldDTO = yAxis.get(0);
ChartFieldCompareDTO compareCalc = chartViewFieldDTO.getCompareCalc();
ChartViewFieldDTO yAxisChartViewFieldDTO = yAxis.get(0);
ChartFieldCompareDTO compareCalc = yAxisChartViewFieldDTO.getCompareCalc();
boolean isYoy = org.apache.commons.lang3.StringUtils.isNotEmpty(compareCalc.getType())
&& !org.apache.commons.lang3.StringUtils.equalsIgnoreCase(compareCalc.getType(), "none");
if (isYoy) {
xAxis.clear();
// 设置维度字段从同环比中获取用户选择的字段
xAxis.addAll(allFields.stream().filter(i -> org.springframework.util.StringUtils.endsWithIgnoreCase(i.getId().toString(), yAxis.get(0).getCompareCalc().getField().toString())).toList());
xAxis.addAll(allFields.stream().filter(i -> org.springframework.util.StringUtils.endsWithIgnoreCase(i.getId().toString(), compareCalc.getField().toString())).toList());
xAxis.get(0).setSort("desc");
if (org.springframework.util.StringUtils.endsWithIgnoreCase("month_mom", compareCalc.getType())) {
xAxis.get(0).setDateStyle("y_M");
}
if (org.springframework.util.StringUtils.endsWithIgnoreCase("day_mom", compareCalc.getType())) {
if(Objects.isNull(compareCalc.getCustom())){
xAxis.get(0).setDateStyle("y_M_d");
}
if (org.springframework.util.StringUtils.endsWithIgnoreCase("year_mom", compareCalc.getType())) {
xAxis.get(0).setDateStyle("y");
}else{
xAxis.get(0).setDateStyle(compareCalc.getCustom().getTimeType());
}
}
formatResult.getAxisMap().put(ChartAxis.xAxis, xAxis);

View File

@ -0,0 +1,86 @@
package io.dataease.chart.charts.impl.table;
import io.dataease.chart.charts.impl.DefaultChartHandler;
import io.dataease.chart.utils.ChartDataBuild;
import io.dataease.engine.sql.SQLProvider;
import io.dataease.engine.trans.Dimension2SQLObj;
import io.dataease.engine.trans.Quota2SQLObj;
import io.dataease.engine.utils.Utils;
import io.dataease.extensions.datasource.dto.DatasourceRequest;
import io.dataease.extensions.datasource.dto.DatasourceSchemaDTO;
import io.dataease.extensions.datasource.model.SQLMeta;
import io.dataease.extensions.datasource.provider.Provider;
import io.dataease.extensions.view.dto.*;
import io.dataease.extensions.view.util.ChartDataUtil;
import io.dataease.extensions.view.util.FieldUtil;
import lombok.Getter;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@Component
public class TableHeatmapHandler extends DefaultChartHandler {
@Getter
private String type = "t-heatmap";
@Override
public AxisFormatResult formatAxis(ChartViewDTO view) {
var result = super.formatAxis(view);
var xAxis = new ArrayList<ChartViewFieldDTO>(view.getXAxis());
xAxis.addAll(view.getXAxisExt());
xAxis.addAll(view.getExtColor());
result.getAxisMap().put(ChartAxis.xAxis, xAxis);
return result;
}
public Map<String, Object> buildResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, List<String[]> data) {
var xAxis = formatResult.getAxisMap().get(ChartAxis.xAxis);
Map<String, Object> result = ChartDataBuild.transChartData( xAxis, new ArrayList<>(), view, data, false);
return result;
}
@Override
public <T extends ChartCalcDataResult> T calcChartResult(ChartViewDTO view, AxisFormatResult formatResult, CustomFilterResult filterResult, Map<String, Object> sqlMap, SQLMeta sqlMeta, Provider provider) {
var dsMap = (Map<Long, DatasourceSchemaDTO>) sqlMap.get("dsMap");
List<String> dsList = new ArrayList<>();
for (Map.Entry<Long, DatasourceSchemaDTO> next : dsMap.entrySet()) {
dsList.add(next.getValue().getType());
}
boolean needOrder = Utils.isNeedOrder(dsList);
boolean crossDs = Utils.isCrossDs(dsMap);
DatasourceRequest datasourceRequest = new DatasourceRequest();
datasourceRequest.setDsList(dsMap);
var xAxis = formatResult.getAxisMap().get(ChartAxis.xAxis);
var yAxis = formatResult.getAxisMap().get(ChartAxis.yAxis);
List<ChartViewFieldDTO> yFields = new ArrayList<>();
yFields.addAll(chartViewManege.transFieldDTO(Collections.singletonList(chartViewManege.createCountField(view.getTableId()))));
yAxis.addAll(yFields);
xAxis = xAxis.stream().filter(i-> !StringUtils.equalsIgnoreCase(i.getDataeaseName(),yAxis.get(0).getDataeaseName())).toList();
var allFields = (List<ChartViewFieldDTO>) filterResult.getContext().get("allFields");
Dimension2SQLObj.dimension2sqlObj(sqlMeta, xAxis, FieldUtil.transFields(allFields), crossDs, dsMap, Utils.getParams(FieldUtil.transFields(allFields)), view.getCalParams(), pluginManage);
Quota2SQLObj.quota2sqlObj(sqlMeta, yAxis, FieldUtil.transFields(allFields), crossDs, dsMap, Utils.getParams(FieldUtil.transFields(allFields)), view.getCalParams(), pluginManage);
String querySql = SQLProvider.createQuerySQL(sqlMeta, true, needOrder, view);
querySql = provider.rebuildSQL(querySql, sqlMeta, crossDs, dsMap);
datasourceRequest.setQuery(querySql);
logger.debug("calcite chart sql: " + querySql);
List<String[]> data = (List<String[]>) provider.fetchResultField(datasourceRequest).get("data");
//自定义排序
data = ChartDataUtil.resultCustomSort(xAxis, data);
//数据重组逻辑可重载
var result = this.buildResult(view, formatResult, filterResult, data);
T calcResult = (T) new ChartCalcDataResult();
calcResult.setData(result);
calcResult.setContext(filterResult.getContext());
calcResult.setQuerySql(querySql);
calcResult.setOriginData(data);
return calcResult;
}
}

View File

@ -137,7 +137,7 @@ public class CoreChartView implements Serializable {
private Long updateTime;
/**
* 缩略图
* 缩略图
*/
private String snapshot;
@ -206,6 +206,16 @@ public class CoreChartView implements Serializable {
*/
private Boolean aggregate;
private String flowMapStartName;
private String flowMapEndName;
/**
* 颜色维度field
*/
private String extColor;
public Long getId() {
return id;
}
@ -510,6 +520,30 @@ public class CoreChartView implements Serializable {
this.aggregate = aggregate;
}
public String getFlowMapStartName() {
return flowMapStartName;
}
public void setFlowMapStartName(String flowMapStartName) {
this.flowMapStartName = flowMapStartName;
}
public String getFlowMapEndName() {
return flowMapEndName;
}
public void setFlowMapEndName(String flowMapEndName) {
this.flowMapEndName = flowMapEndName;
}
public String getExtColor() {
return extColor;
}
public void setExtColor(String extColor) {
this.extColor = extColor;
}
@Override
public String toString() {
return "CoreChartView{" +
@ -551,6 +585,9 @@ public class CoreChartView implements Serializable {
", copyFrom = " + copyFrom +
", copyId = " + copyId +
", aggregate = " + aggregate +
", flowMapStartName=" + flowMapStartName +
", flowMapEndName=" + flowMapEndName +
", extColor=" + extColor +
"}";
}
}

View File

@ -144,6 +144,7 @@ public class ChartDataManage {
// 过滤来自仪表板的条件
List<ChartExtFilterDTO> extFilterList = new ArrayList<>();
//组件过滤条件
List<SqlVariableDetails> sqlVariables = datasetGroupManage.getSqlParams(Collections.singletonList(view.getTableId()));
if (ObjectUtils.isNotEmpty(chartExtRequest.getFilter())) {
for (ChartExtFilterDTO request : chartExtRequest.getFilter()) {
// 解析多个fieldId,fieldId是一个逗号分隔的字符串
@ -153,7 +154,6 @@ public class ChartDataManage {
}
boolean hasParameters = false;
List<SqlVariableDetails> sqlVariables = datasetGroupManage.getSqlParams(Collections.singletonList(view.getTableId()));
if (CollectionUtils.isNotEmpty(sqlVariables)) {
for (SqlVariableDetails parameter : Optional.ofNullable(request.getParameters()).orElse(new ArrayList<>())) {
String parameterId = StringUtils.endsWith(parameter.getId(), START_END_SEPARATOR) ? parameter.getId().split(START_END_SEPARATOR)[0] : parameter.getId();
@ -234,18 +234,35 @@ public class ChartDataManage {
//联动过滤条件和外部参数过滤条件全部加上
if (ObjectUtils.isNotEmpty(filters)) {
for (ChartExtFilterDTO request : filters) {
DatasetTableFieldDTO datasetTableField = datasetTableFieldManage.selectById(Long.valueOf(request.getFieldId()));
request.setDatasetTableField(datasetTableField);
request.setFilterType(2);
// 相同数据集
if (Objects.equals(datasetTableField.getDatasetGroupId(), view.getTableId())) {
if (ObjectUtils.isNotEmpty(request.getViewIds())) {
if (request.getViewIds().contains(view.getId())) {
// 包含 DE 的为数据集参数
if(request.getFieldId().contains("DE")){
// 组装sql 参数原始数据
if (CollectionUtils.isNotEmpty(sqlVariables)) {
for(SqlVariableDetails sourceVariables : sqlVariables){
if(sourceVariables.getId().equals(request.getFieldId())){
if(CollectionUtils.isEmpty(request.getParameters())){
request.setParameters(new ArrayList<>());
}
request.getParameters().add(sourceVariables);
}
}
}
}else {
DatasetTableFieldDTO datasetTableField = datasetTableFieldManage.selectById(Long.valueOf(request.getFieldId()));
request.setDatasetTableField(datasetTableField);
request.setFilterType(2);
// 相同数据集
if (Objects.equals(datasetTableField.getDatasetGroupId(), view.getTableId())) {
if (ObjectUtils.isNotEmpty(request.getViewIds())) {
if (request.getViewIds().contains(view.getId())) {
extFilterList.add(request);
}
} else {
extFilterList.add(request);
}
} else {
extFilterList.add(request);
}
}
}
}
@ -604,7 +621,8 @@ public class ChartDataManage {
if (StringUtils.equalsIgnoreCase(view.getType(), "table-pivot")
|| StringUtils.containsIgnoreCase(view.getType(), "group")
|| ("antv".equalsIgnoreCase(view.getRender()) && "line".equalsIgnoreCase(view.getType()))
|| StringUtils.equalsIgnoreCase(view.getType(), "flow-map")) {
|| StringUtils.equalsIgnoreCase(view.getType(), "flow-map")
|| StringUtils.equalsIgnoreCase(view.getType(), "t-heatmap")) {
xAxis.addAll(xAxisExt);
}
List<ChartViewFieldDTO> yAxis = new ArrayList<>(view.getYAxis());
@ -754,16 +772,22 @@ public class ChartDataManage {
public void saveChartViewFromVisualization(String checkData, Long sceneId, Map<Long, ChartViewDTO> chartViewsInfo) {
if (!MapUtils.isEmpty(chartViewsInfo)) {
List<Long> disuseChartIdList = new ArrayList<>();
chartViewsInfo.forEach((key, chartViewDTO) -> {
if (checkData.indexOf(chartViewDTO.getId() + "") > -1) {
if (checkData.contains(chartViewDTO.getId() + "")) {
try {
chartViewDTO.setSceneId(sceneId);
chartViewManege.save(chartViewDTO);
} catch (Exception e) {
DEException.throwException(e);
}
} else {
disuseChartIdList.add(chartViewDTO.getId());
}
});
if (CollectionUtils.isNotEmpty(disuseChartIdList)) {
chartViewManege.disuse(disuseChartIdList);
}
}
}
}

View File

@ -26,6 +26,7 @@ import io.dataease.extensions.datasource.model.SQLObj;
import io.dataease.extensions.view.dto.*;
import io.dataease.extensions.view.filter.FilterTreeObj;
import io.dataease.i18n.Translator;
import io.dataease.license.config.XpackInteract;
import io.dataease.utils.BeanUtils;
import io.dataease.utils.IDUtils;
import io.dataease.utils.JsonUtil;
@ -98,6 +99,9 @@ public class ChartViewManege {
coreChartViewMapper.deleteById(id);
}
@XpackInteract(value = "chartViewManage")
public void disuse(List<Long> chartIdList) {}
@Transactional
public void deleteBySceneId(Long sceneId, List<Long> chartIds) {
QueryWrapper<CoreChartView> wrapper = new QueryWrapper<>();
@ -252,6 +256,7 @@ public class ChartViewManege {
public ChartBaseVO chartBaseInfo(Long id) {
ChartBasePO po = extChartViewMapper.queryChart(id);
if (ObjectUtils.isEmpty(po)) return null;
ChartBaseVO vo = BeanUtils.copyBean(new ChartBaseVO(), po);
TypeReference<List<ChartViewFieldDTO>> tokenType = new TypeReference<>() {};
vo.setXAxis(JsonUtil.parseList(po.getXAxis(), tokenType));
@ -324,6 +329,9 @@ public class ChartViewManege {
record.setDrillFields(objectMapper.writeValueAsString(dto.getDrillFields()));
record.setCustomFilter(objectMapper.writeValueAsString(dto.getCustomFilter()));
record.setViewFields(objectMapper.writeValueAsString(dto.getViewFields()));
record.setFlowMapStartName(objectMapper.writeValueAsString(dto.getFlowMapStartName()));
record.setFlowMapEndName(objectMapper.writeValueAsString(dto.getFlowMapEndName()));
record.setExtColor(objectMapper.writeValueAsString(dto.getExtColor()));
return record;
}
@ -349,6 +357,9 @@ public class ChartViewManege {
dto.setDrillFields(JsonUtil.parseList(record.getDrillFields(), tokenType));
dto.setCustomFilter(JsonUtil.parseObject(record.getCustomFilter(), FilterTreeObj.class));
dto.setViewFields(JsonUtil.parseList(record.getViewFields(), tokenType));
dto.setFlowMapStartName(JsonUtil.parseList(record.getFlowMapStartName(), tokenType));
dto.setFlowMapEndName(JsonUtil.parseList(record.getFlowMapEndName(), tokenType));
dto.setExtColor(JsonUtil.parseList(record.getExtColor(), tokenType));
return dto;

View File

@ -112,7 +112,8 @@ public class DatasetDataManage {
sql = provider.transSqlDialect(sql, datasourceRequest.getDsList());
} else {
// parser sql params and replace default value
String originSql = SqlparserUtils.handleVariableDefaultValue(new String(Base64.getDecoder().decode(tableInfoDTO.getSql())), datasetTableDTO.getSqlVariableDetails(), false, false, null, false, datasourceRequest.getDsList(), pluginManage);
String originSql = provider.replaceComment(new String(Base64.getDecoder().decode(tableInfoDTO.getSql())));
originSql = SqlparserUtils.handleVariableDefaultValue(originSql, datasetTableDTO.getSqlVariableDetails(), false, false, null, false, datasourceRequest.getDsList(), pluginManage);
// add sql table schema
sql = SQLUtils.buildOriginPreviewSql(SqlPlaceholderConstants.TABLE_PLACEHOLDER, 0, 0);
@ -344,13 +345,16 @@ public class DatasetDataManage {
dsMap.put(datasourceSchemaDTO.getId(), datasourceSchemaDTO);
DatasourceRequest datasourceRequest = new DatasourceRequest();
datasourceRequest.setDsList(dsMap);
Provider provider = ProviderFactory.getProvider(datasourceSchemaDTO.getType());
// parser sql params and replace default value
String originSql = SqlparserUtils.handleVariableDefaultValue(datasetSQLManage.subPrefixSuffixChar(new String(Base64.getDecoder().decode(dto.getSql()))), dto.getSqlVariableDetails(), true, true, null, false, dsMap, pluginManage);
String originSql = provider.replaceComment(new String(Base64.getDecoder().decode(dto.getSql())));
originSql = SqlparserUtils.handleVariableDefaultValue(datasetSQLManage.subPrefixSuffixChar(originSql), dto.getSqlVariableDetails(), true, true, null, false, dsMap, pluginManage);
// sql 作为临时表外层加上limit
String sql;
Provider provider = ProviderFactory.getProvider(datasourceSchemaDTO.getType());
if (Utils.isNeedOrder(List.of(datasourceSchemaDTO.getType()))) {
// 先根据sql获取表字段
String sqlField = SQLUtils.buildOriginPreviewSql(SqlPlaceholderConstants.TABLE_PLACEHOLDER, 0, 0);

View File

@ -19,7 +19,9 @@ import io.dataease.extensions.datasource.dto.DatasetTableDTO;
import io.dataease.extensions.datasource.dto.DatasetTableFieldDTO;
import io.dataease.extensions.datasource.dto.DatasourceSchemaDTO;
import io.dataease.extensions.datasource.dto.DsTypeDTO;
import io.dataease.extensions.datasource.factory.ProviderFactory;
import io.dataease.extensions.datasource.model.SQLObj;
import io.dataease.extensions.datasource.provider.Provider;
import io.dataease.extensions.datasource.vo.DatasourceConfiguration;
import io.dataease.extensions.datasource.vo.XpackPluginsDatasourceVO;
import io.dataease.extensions.view.dto.ChartExtFilterDTO;
@ -64,25 +66,37 @@ public class DatasetSQLManage {
private List<SqlVariableDetails> filterParameters(ChartExtRequest chartExtRequest, Long datasetTableId) {
List<SqlVariableDetails> parameters = new ArrayList<>();
if (chartExtRequest != null && ObjectUtils.isNotEmpty(chartExtRequest.getOuterParamsFilters())) {
for (ChartExtFilterDTO filterDTO : chartExtRequest.getOuterParamsFilters()) {
if (CollectionUtils.isEmpty(filterDTO.getValue())) {
continue;
}
filterParametersAdaptor(parameters,filterDTO,datasetTableId);
}
}
if (chartExtRequest != null && ObjectUtils.isNotEmpty(chartExtRequest.getFilter())) {
for (ChartExtFilterDTO filterDTO : chartExtRequest.getFilter()) {
if (CollectionUtils.isEmpty(filterDTO.getValue())) {
continue;
}
if (ObjectUtils.isNotEmpty(filterDTO.getParameters())) {
for (SqlVariableDetails parameter : filterDTO.getParameters()) {
if (parameter.getDatasetTableId().equals(datasetTableId)) {
parameter.setValue(filterDTO.getValue());
parameter.setOperator(filterDTO.getOperator());
parameters.add(parameter);
}
}
}
filterParametersAdaptor(parameters,filterDTO,datasetTableId);
}
}
return parameters;
}
private void filterParametersAdaptor(List<SqlVariableDetails> parameters,ChartExtFilterDTO filterDTO,Long datasetTableId){
if (ObjectUtils.isNotEmpty(filterDTO.getParameters())) {
for (SqlVariableDetails parameter : filterDTO.getParameters()) {
if (parameter.getDatasetTableId().equals(datasetTableId)) {
parameter.setValue(filterDTO.getValue());
parameter.setOperator(filterDTO.getOperator());
parameters.add(parameter);
}
}
}
}
public Map<String, Object> getUnionSQLForEdit(DatasetGroupInfoDTO dataTableInfoDTO, ChartExtRequest chartExtRequest) throws Exception {
Map<Long, DatasourceSchemaDTO> dsMap = new LinkedHashMap<>();
List<UnionDTO> union = dataTableInfoDTO.getUnion();
@ -430,8 +444,10 @@ public class DatasetSQLManage {
if (StringUtils.equalsIgnoreCase(currentDs.getType(), DatasetTableTypeConstants.DATASET_TABLE_DB)) {
tableObj = SQLObj.builder().tableSchema(tableSchema).tableName(infoDTO.getTable()).tableAlias(tableAlias).build();
} else if (StringUtils.equalsIgnoreCase(currentDs.getType(), DatasetTableTypeConstants.DATASET_TABLE_SQL)) {
Provider provider = ProviderFactory.getProvider(dsMap.entrySet().iterator().next().getValue().getType());
// parser sql params and replace default value
String sql = SqlparserUtils.handleVariableDefaultValue(new String(Base64.getDecoder().decode(infoDTO.getSql())), currentDs.getSqlVariableDetails(), false, isFromDataSet, parameters, isCross, dsMap, pluginManage);
String sql = provider.replaceComment(new String(Base64.getDecoder().decode(infoDTO.getSql())));
sql = SqlparserUtils.handleVariableDefaultValue(sql, currentDs.getSqlVariableDetails(), false, isFromDataSet, parameters, isCross, dsMap, pluginManage);
// add table schema
if (isCross) {
sql = SqlUtils.addSchema(sql, tableSchema);

View File

@ -382,7 +382,7 @@ public class CalciteProvider extends Provider {
// schema
ResultSet resultSet = null;
try (ConnectionObj con = getConnection(datasourceRequest.getDatasource()); PreparedStatement statement = getPreparedStatement(con.getConnection(), datasourceConfiguration.getQueryTimeout(), datasourceRequest.getQuery())) {
try (ConnectionObj con = getConnection(datasourceRequest.getDatasource()); Statement statement = getPreparedStatement(con.getConnection(), datasourceConfiguration.getQueryTimeout(), datasourceRequest.getQuery(), datasourceRequest.getTableFieldWithValues())) {
if (DatasourceConfiguration.DatasourceType.valueOf(value.getType()) == DatasourceConfiguration.DatasourceType.oracle) {
statement.executeUpdate("ALTER SESSION SET CURRENT_SCHEMA = " + datasourceConfiguration.getSchema());
}
@ -390,12 +390,13 @@ public class CalciteProvider extends Provider {
if (CollectionUtils.isNotEmpty(datasourceRequest.getTableFieldWithValues())) {
LogUtil.info("execWithPreparedStatement sql: " + datasourceRequest.getQuery());
for (int i = 0; i < datasourceRequest.getTableFieldWithValues().size(); i++) {
statement.setObject(i + 1, datasourceRequest.getTableFieldWithValues().get(i).getValue(), datasourceRequest.getTableFieldWithValues().get(i).getType());
((PreparedStatement) statement).setObject(i + 1, datasourceRequest.getTableFieldWithValues().get(i).getValue(), datasourceRequest.getTableFieldWithValues().get(i).getType());
LogUtil.info("execWithPreparedStatement param[" + (i + 1) + "]: " + datasourceRequest.getTableFieldWithValues().get(i).getValue());
}
resultSet = ((PreparedStatement) statement).executeQuery();
} else {
resultSet = statement.executeQuery(datasourceRequest.getQuery());
}
resultSet = statement.executeQuery();
fieldList = getField(resultSet, datasourceRequest);
dataList = getData(resultSet, datasourceRequest);
} catch (SQLException e) {
@ -426,7 +427,7 @@ public class CalciteProvider extends Provider {
// schema
ResultSet resultSet = null;
try (ConnectionObj con = getConnection(datasourceRequest.getDatasource()); PreparedStatement statement = getPreparedStatement(con.getConnection(), datasourceConfiguration.getQueryTimeout(), datasourceRequest.getQuery())) {
try (ConnectionObj con = getConnection(datasourceRequest.getDatasource()); Statement statement = getPreparedStatement(con.getConnection(), datasourceConfiguration.getQueryTimeout(), datasourceRequest.getQuery(), datasourceRequest.getTableFieldWithValues())) {
if (DatasourceConfiguration.DatasourceType.valueOf(value.getType()) == DatasourceConfiguration.DatasourceType.oracle) {
statement.executeUpdate("ALTER SESSION SET CURRENT_SCHEMA = " + datasourceConfiguration.getSchema());
}
@ -434,13 +435,14 @@ public class CalciteProvider extends Provider {
if (CollectionUtils.isNotEmpty(datasourceRequest.getTableFieldWithValues())) {
LogUtil.info("execWithPreparedStatement sql: " + datasourceRequest.getQuery());
for (int i = 0; i < datasourceRequest.getTableFieldWithValues().size(); i++) {
statement.setObject(i + 1, datasourceRequest.getTableFieldWithValues().get(i).getValue(), datasourceRequest.getTableFieldWithValues().get(i).getType());
((PreparedStatement) statement).setObject(i + 1, datasourceRequest.getTableFieldWithValues().get(i).getValue(), datasourceRequest.getTableFieldWithValues().get(i).getType());
LogUtil.info("execWithPreparedStatement param[" + (i + 1) + "]: " + datasourceRequest.getTableFieldWithValues().get(i).getValue());
}
((PreparedStatement) statement).execute();
} else {
statement.execute(datasourceRequest.getQuery());
}
statement.execute();
} catch (SQLException e) {
DEException.throwException("SQL ERROR: " + e.getMessage());
} catch (Exception e) {
@ -465,7 +467,7 @@ public class CalciteProvider extends Provider {
// schema
ResultSet resultSet = null;
try (ConnectionObj con = getConnection(datasourceRequest.getDatasource()); PreparedStatement statement = getPreparedStatement(con.getConnection(), datasourceConfiguration.getQueryTimeout(), datasourceRequest.getQuery())) {
try (ConnectionObj con = getConnection(datasourceRequest.getDatasource()); Statement statement = getPreparedStatement(con.getConnection(), datasourceConfiguration.getQueryTimeout(), datasourceRequest.getQuery(), datasourceRequest.getTableFieldWithValues())) {
if (DatasourceConfiguration.DatasourceType.valueOf(value.getType()) == DatasourceConfiguration.DatasourceType.oracle) {
statement.executeUpdate("ALTER SESSION SET CURRENT_SCHEMA = " + datasourceConfiguration.getSchema());
}
@ -473,13 +475,14 @@ public class CalciteProvider extends Provider {
if (CollectionUtils.isNotEmpty(datasourceRequest.getTableFieldWithValues())) {
LogUtil.info("execWithPreparedStatement sql: " + datasourceRequest.getQuery());
for (int i = 0; i < datasourceRequest.getTableFieldWithValues().size(); i++) {
statement.setObject(i + 1, datasourceRequest.getTableFieldWithValues().get(i).getValue(), datasourceRequest.getTableFieldWithValues().get(i).getType());
((PreparedStatement) statement).setObject(i + 1, datasourceRequest.getTableFieldWithValues().get(i).getValue(), datasourceRequest.getTableFieldWithValues().get(i).getType());
LogUtil.info("execWithPreparedStatement param[" + (i + 1) + "]: " + datasourceRequest.getTableFieldWithValues().get(i).getValue());
}
return ((PreparedStatement) statement).executeUpdate();
} else {
return statement.executeUpdate(datasourceRequest.getQuery());
}
return statement.executeUpdate();
} catch (SQLException e) {
DEException.throwException("SQL ERROR: " + e.getMessage());
} catch (Exception e) {
@ -1158,16 +1161,22 @@ public class CalciteProvider extends Provider {
return stat;
}
public PreparedStatement getPreparedStatement(Connection connection, int queryTimeout, String sql) throws Exception {
public Statement getPreparedStatement(Connection connection, int queryTimeout, String sql, List<TableFieldWithValue> values) throws Exception {
if (connection == null) {
throw new Exception("Failed to get connection!");
}
PreparedStatement stat = connection.prepareStatement(sql);
try {
stat.setQueryTimeout(queryTimeout);
} catch (Exception e) {
if (CollectionUtils.isNotEmpty(values)) {
PreparedStatement stat = null;
try {
stat = connection.prepareStatement(sql);
stat.setQueryTimeout(queryTimeout);
} catch (Exception e) {
DEException.throwException(e.getMessage());
}
return stat;
} else {
return getStatement(connection, queryTimeout);
}
return stat;
}
protected boolean isDefaultClassLoader(String customDriver) {

View File

@ -1,5 +1,6 @@
package io.dataease.visualization.dao.auto.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
@ -9,7 +10,7 @@ import java.io.Serializable;
* </p>
*
* @author fit2cloud
* @since 2024-03-08
* @since 2024-08-21
*/
@TableName("visualization_outer_params_target_view_info")
public class VisualizationOuterParamsTargetViewInfo implements Serializable {
@ -19,6 +20,7 @@ public class VisualizationOuterParamsTargetViewInfo implements Serializable {
/**
* 主键
*/
@TableId("target_id")
private String targetId;
/**
@ -27,10 +29,15 @@ public class VisualizationOuterParamsTargetViewInfo implements Serializable {
private String paramsInfoId;
/**
* 联动视图ID
* 联动视图ID/联动过滤项ID
*/
private String targetViewId;
/**
* 联动数据集id/联动过滤组件id
*/
private String targetDsId;
/**
* 联动字段ID
*/
@ -70,6 +77,14 @@ public class VisualizationOuterParamsTargetViewInfo implements Serializable {
this.targetViewId = targetViewId;
}
public String getTargetDsId() {
return targetDsId;
}
public void setTargetDsId(String targetDsId) {
this.targetDsId = targetDsId;
}
public String getTargetFieldId() {
return targetFieldId;
}
@ -100,6 +115,7 @@ public class VisualizationOuterParamsTargetViewInfo implements Serializable {
"targetId = " + targetId +
", paramsInfoId = " + paramsInfoId +
", targetViewId = " + targetViewId +
", targetDsId = " + targetDsId +
", targetFieldId = " + targetFieldId +
", copyFrom = " + copyFrom +
", copyId = " + copyId +

View File

@ -10,7 +10,7 @@ import org.apache.ibatis.annotations.Mapper;
* </p>
*
* @author fit2cloud
* @since 2024-03-08
* @since 2024-08-21
*/
@Mapper
public interface VisualizationOuterParamsTargetViewInfoMapper extends BaseMapper<VisualizationOuterParamsTargetViewInfo> {

View File

@ -1,6 +1,7 @@
package io.dataease.visualization.dao.ext.mapper;
import io.dataease.api.dataset.vo.CoreDatasetGroupVO;
import io.dataease.api.visualization.dto.VisualizationOuterParamsDTO;
import io.dataease.api.visualization.dto.VisualizationOuterParamsInfoDTO;
import org.apache.ibatis.annotations.Mapper;
@ -20,4 +21,6 @@ public interface ExtVisualizationOuterParamsMapper {
void deleteOuterParamsWithVisualizationId(@Param("visualizationId") String visualizationId);
List<VisualizationOuterParamsInfoDTO> getVisualizationOuterParamsInfo(@Param("visualizationId") String visualizationId);
List<CoreDatasetGroupVO> queryDsWithVisualizationId(@Param("visualizationId") String visualizationId);
}

View File

@ -1,10 +1,20 @@
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.dataset.dao.auto.entity.CoreDatasetTable;
import io.dataease.dataset.dao.auto.mapper.CoreDatasetTableMapper;
import io.dataease.engine.constant.DeTypeConstants;
import io.dataease.extensions.view.dto.SqlVariableDetails;
import io.dataease.utils.BeanUtils;
import io.dataease.utils.JsonUtil;
import io.dataease.visualization.dao.auto.entity.VisualizationOuterParams;
import io.dataease.visualization.dao.auto.entity.VisualizationOuterParamsInfo;
import io.dataease.visualization.dao.auto.entity.VisualizationOuterParamsTargetViewInfo;
@ -13,14 +23,13 @@ import io.dataease.visualization.dao.auto.mapper.VisualizationOuterParamsMapper;
import io.dataease.visualization.dao.auto.mapper.VisualizationOuterParamsTargetViewInfoMapper;
import io.dataease.visualization.dao.ext.mapper.ExtVisualizationOuterParamsMapper;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.*;
import java.util.stream.Collectors;
/**
@ -41,12 +50,21 @@ public class VisualizationOuterParamsService implements VisualizationOuterParams
@Resource
private VisualizationOuterParamsTargetViewInfoMapper outerParamsTargetViewInfoMapper;
@Resource
private CoreDatasetTableMapper coreDatasetTableMapper;
@Override
public VisualizationOuterParamsDTO queryWithVisualizationId(String visualizationId) {
VisualizationOuterParamsDTO visualizationOuterParamsDTO = extOuterParamsMapper.queryWithVisualizationId(visualizationId);
return visualizationOuterParamsDTO;
}
@Override
public VisualizationOuterParamsDTO queryWithVisualizationIdDS(String dvId) {
return null;
}
@Override
public void updateOuterParamsSet(VisualizationOuterParamsDTO outerParamsDTO) {
String visualizationId = outerParamsDTO.getVisualizationId();
@ -85,4 +103,32 @@ public class VisualizationOuterParamsService implements VisualizationOuterParams
List<VisualizationOuterParamsInfoDTO> result = extOuterParamsMapper.getVisualizationOuterParamsInfo(visualizationId);
return new VisualizationOuterParamsBaseResponse(Optional.ofNullable(result).orElse(new ArrayList<>()).stream().collect(Collectors.toMap(VisualizationOuterParamsInfoDTO::getSourceInfo, VisualizationOuterParamsInfoDTO::getTargetInfoList)));
}
@Override
public List<CoreDatasetGroupVO> queryDsWithVisualizationId(String visualizationId) {
List<CoreDatasetGroupVO> result = extOuterParamsMapper.queryDsWithVisualizationId(visualizationId);
if(!CollectionUtils.isEmpty(result)){
result.forEach(coreDatasetGroupVO -> {
List<CoreDatasetTableFieldVO> fields = coreDatasetGroupVO.getDatasetFields();
QueryWrapper<CoreDatasetTable> wrapper = new QueryWrapper<>();
wrapper.eq("dataset_group_id", coreDatasetGroupVO.getId());
List<CoreDatasetTable> tableResult = coreDatasetTableMapper.selectList(wrapper);
if(!CollectionUtils.isEmpty(tableResult)){
tableResult.forEach(coreDatasetTable -> {
String sqlVarDetail = coreDatasetTable.getSqlVariableDetails();
if(StringUtils.isNotEmpty(sqlVarDetail)){
TypeReference<List<SqlVariableDetails>> listTypeReference = new TypeReference<List<SqlVariableDetails>>() {
};
List<SqlVariableDetails> defaultsSqlVariableDetails = JsonUtil.parseList(sqlVarDetail, listTypeReference);
defaultsSqlVariableDetails.forEach(sqlVariableDetails -> {
String varFieldId = coreDatasetTable.getId()+"|DE|"+sqlVariableDetails.getVariableName();
fields.add(new CoreDatasetTableFieldVO(varFieldId,sqlVariableDetails.getVariableName(), DeTypeConstants.DE_STRING));
});
}
});
}
});
}
return result;
}
}

View File

@ -6,3 +6,19 @@ alter table `core_dataset_table_field` add params text null comment '计算字
alter table `core_datasource`
add `enable_data_fill` tinyint default 0 null comment '启用数据填报功能';
ALTER TABLE `visualization_outer_params_target_view_info`
MODIFY COLUMN `target_view_id` varchar(50) NULL DEFAULT NULL COMMENT '联动视图ID/联动过滤项ID' ,
ADD COLUMN `target_ds_id` varchar(50) NULL COMMENT '联动数据集id/联动过滤组件id' ;
alter table `core_chart_view`
add flow_map_start_name longtext comment '流向地图起点名称field';
alter table `core_chart_view`
add flow_map_end_name longtext comment '流向地图终点名称field';
alter table `core_chart_view`
add ext_color longtext comment '颜色维度field';
update visualization_outer_params_target_view_info tvi INNER JOIN core_chart_view ccv on tvi.target_view_id = ccv.id
set tvi.target_ds_id = ccv.table_id

View File

@ -57,3 +57,16 @@ CREATE TABLE `xpack_threshold_instance`
);
ALTER TABLE `visualization_outer_params_target_view_info`
MODIFY COLUMN `target_view_id` varchar(50) NULL DEFAULT NULL COMMENT '联动视图ID/联动过滤项ID' ,
ADD COLUMN `target_ds_id` varchar(50) NULL COMMENT '联动数据集id/联动过滤组件id' ;
alter table `core_chart_view`
add flow_map_start_name longtext comment '流向地图起点名称field';
alter table `core_chart_view`
add flow_map_end_name longtext comment '流向地图终点名称field';
alter table `core_chart_view`
add ext_color longtext comment '颜色维度field';
update visualization_outer_params_target_view_info tvi INNER JOIN core_chart_view ccv on tvi.target_view_id = ccv.id
set tvi.target_ds_id = ccv.table_id

View File

@ -160,7 +160,9 @@
FROM data_visualization_info
where data_visualization_info.delete_flag = 0
and data_visualization_info.id = #{dvId}
and data_visualization_info.type = #{dvType}
<if test="dvType">
and data_visualization_info.type = #{dvType}
</if>
</select>
<select id="findRecent" resultType="io.dataease.visualization.dao.ext.po.VisualizationResourcePO">

View File

@ -28,9 +28,21 @@
</collection>
</resultMap>
<resultMap id="BaseDsResultMapDTO" type="io.dataease.api.dataset.vo.CoreDatasetGroupVO">
<collection property="datasetFields" ofType="io.dataease.api.dataset.vo.CoreDatasetTableFieldVO"
column="{dataset_group_id=id}"
select="getDsFieldInfo">
</collection>
<collection property="datasetViews" ofType="io.dataease.api.chart.vo.ChartBaseVO"
column="{dataset_group_id=id,visualizationId = visualizationId}"
select="getViewInfo">
</collection>
</resultMap>
<resultMap id="OuterParamsInfoMap" type="io.dataease.api.visualization.dto.VisualizationOuterParamsInfoDTO" extends="BaseResultMapParamsInfo">
<collection property="targetViewInfoList" ofType="io.dataease.visualization.dao.auto.entity.VisualizationOuterParamsTargetViewInfo">
<result column="target_view_id" jdbcType="VARCHAR" property="targetViewId"/>
<result column="target_ds_id" jdbcType="VARCHAR" property="targetDsId"/>
<result column="target_field_id" jdbcType="VARCHAR" property="targetFieldId"/>
</collection>
</resultMap>
@ -49,6 +61,7 @@
popi.param_name,
ifnull( popi.checked, 0 ) AS checked,
poptvi.target_view_id,
poptvi.target_ds_id,
poptvi.target_field_id
FROM
visualization_outer_params pop
@ -114,5 +127,34 @@
and popi.checked=1
</select>
<select id="queryDsWithVisualizationId" resultMap="BaseDsResultMapDTO">
SELECT DISTINCT
cdg.*,#{visualizationId} as visualizationId
FROM
core_dataset_group cdg
INNER JOIN core_chart_view ccv ON cdg.id = ccv.table_id and ccv.type != 'VQuery'
INNER JOIN data_visualization_info dvi ON ccv.scene_id = dvi.id
WHERE
ccv.scene_id = #{visualizationId}
AND dvi.id = #{visualizationId}
AND LOCATE(ccv.id, dvi.component_data)
</select>
<select id="getDsFieldInfo" resultType="io.dataease.api.dataset.vo.CoreDatasetTableFieldVO">
select cdtf.*,cdtf.id as attachId from core_dataset_table_field cdtf where cdtf.dataset_group_id = #{dataset_group_id}
</select>
<select id="getViewInfo" resultType="io.dataease.api.chart.vo.ChartBaseVO">
SELECT DISTINCT
ccv.id as chartId,ccv.title as chartName,ccv.type as chartType
FROM
core_chart_view ccv
INNER JOIN data_visualization_info dvi ON ccv.scene_id = dvi.id
WHERE
ccv.table_id = #{dataset_group_id}
AND ccv.type != 'VQuery'
AND dvi.id = #{visualizationId}
AND LOCATE(ccv.id, dvi.component_data)
</select>
</mapper>

View File

@ -107,3 +107,11 @@ export const export2AppCheck = params => {
loading: true
})
}
export const queryOuterParamsDsInfo = async dvId => {
return request.get({
url: '/outerParams/queryDsWithVisualizationId/' + dvId,
method: 'get',
loading: false
})
}

View File

@ -0,0 +1,18 @@
<svg width="80" height="56" viewBox="0 0 80 56" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13 6C13 5.44772 13.4477 5 14 5H24C24.5523 5 25 5.44772 25 6V14C25 14.5523 24.5523 15 24 15H14C13.4477 15 13 14.5523 13 14V6Z" fill="#244EB3"/>
<path d="M13 18C13 17.4477 13.4477 17 14 17H24C24.5523 17 25 17.4477 25 18V26C25 26.5523 24.5523 27 24 27H14C13.4477 27 13 26.5523 13 26V18Z" fill="#3370FF"/>
<path d="M13 30C13 29.4477 13.4477 29 14 29H24C24.5523 29 25 29.4477 25 30V38C25 38.5523 24.5523 39 24 39H14C13.4477 39 13 38.5523 13 38V30Z" fill="#244EB3"/>
<path d="M13 42C13 41.4477 13.4477 41 14 41H24C24.5523 41 25 41.4477 25 42V50C25 50.5523 24.5523 51 24 51H14C13.4477 51 13 50.5523 13 50V42Z" fill="#244EB3"/>
<path d="M27 6C27 5.44772 27.4477 5 28 5H38C38.5523 5 39 5.44772 39 6V14C39 14.5523 38.5523 15 38 15H28C27.4477 15 27 14.5523 27 14V6Z" fill="#142D66"/>
<path d="M27 18C27 17.4477 27.4477 17 28 17H38C38.5523 17 39 17.4477 39 18V26C39 26.5523 38.5523 27 38 27H28C27.4477 27 27 26.5523 27 26V18Z" fill="#244EB3"/>
<path d="M27 30C27 29.4477 27.4477 29 28 29H38C38.5523 29 39 29.4477 39 30V38C39 38.5523 38.5523 39 38 39H28C27.4477 39 27 38.5523 27 38V30Z" fill="#142D66"/>
<path d="M27 42C27 41.4477 27.4477 41 28 41H38C38.5523 41 39 41.4477 39 42V50C39 50.5523 38.5523 51 38 51H28C27.4477 51 27 50.5523 27 50V42Z" fill="#3370FF"/>
<path d="M41 6C41 5.44772 41.4477 5 42 5H52C52.5523 5 53 5.44772 53 6V14C53 14.5523 52.5523 15 52 15H42C41.4477 15 41 14.5523 41 14V6Z" fill="#244EB3"/>
<path d="M41 18C41 17.4477 41.4477 17 42 17H52C52.5523 17 53 17.4477 53 18V26C53 26.5523 52.5523 27 52 27H42C41.4477 27 41 26.5523 41 26V18Z" fill="#3370FF"/>
<path d="M41 30C41 29.4477 41.4477 29 42 29H52C52.5523 29 53 29.4477 53 30V38C53 38.5523 52.5523 39 52 39H42C41.4477 39 41 38.5523 41 38V30Z" fill="#244EB3"/>
<path d="M41 42C41 41.4477 41.4477 41 42 41H52C52.5523 41 53 41.4477 53 42V50C53 50.5523 52.5523 51 52 51H42C41.4477 51 41 50.5523 41 50V42Z" fill="#142D66"/>
<path d="M55 6C55 5.44772 55.4477 5 56 5H66C66.5523 5 67 5.44772 67 6V14C67 14.5523 66.5523 15 66 15H56C55.4477 15 55 14.5523 55 14V6Z" fill="#244EB3"/>
<path d="M55 18C55 17.4477 55.4477 17 56 17H66C66.5523 17 67 17.4477 67 18V26C67 26.5523 66.5523 27 66 27H56C55.4477 27 55 26.5523 55 26V18Z" fill="#142D66"/>
<path d="M55 30C55 29.4477 55.4477 29 56 29H66C66.5523 29 67 29.4477 67 30V38C67 38.5523 66.5523 39 66 39H56C55.4477 39 55 38.5523 55 38V30Z" fill="#244EB3"/>
<path d="M55 42C55 41.4477 55.4477 41 56 41H66C66.5523 41 67 41.4477 67 42V50C67 50.5523 66.5523 51 66 51H56C55.4477 51 55 50.5523 55 50V42Z" fill="#244EB3"/>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -0,0 +1,18 @@
<svg width="80" height="56" viewBox="0 0 80 56" xmlns="http://www.w3.org/2000/svg">
<path d="M13 6C13 5.44772 13.4477 5 14 5H24C24.5523 5 25 5.44772 25 6V14C25 14.5523 24.5523 15 24 15H14C13.4477 15 13 14.5523 13 14V6Z"/>
<path d="M13 18C13 17.4477 13.4477 17 14 17H24C24.5523 17 25 17.4477 25 18V26C25 26.5523 24.5523 27 24 27H14C13.4477 27 13 26.5523 13 26V18Z"/>
<path d="M13 30C13 29.4477 13.4477 29 14 29H24C24.5523 29 25 29.4477 25 30V38C25 38.5523 24.5523 39 24 39H14C13.4477 39 13 38.5523 13 38V30Z"/>
<path d="M13 42C13 41.4477 13.4477 41 14 41H24C24.5523 41 25 41.4477 25 42V50C25 50.5523 24.5523 51 24 51H14C13.4477 51 13 50.5523 13 50V42Z"/>
<path d="M27 6C27 5.44772 27.4477 5 28 5H38C38.5523 5 39 5.44772 39 6V14C39 14.5523 38.5523 15 38 15H28C27.4477 15 27 14.5523 27 14V6Z"/>
<path d="M27 18C27 17.4477 27.4477 17 28 17H38C38.5523 17 39 17.4477 39 18V26C39 26.5523 38.5523 27 38 27H28C27.4477 27 27 26.5523 27 26V18Z"/>
<path d="M27 30C27 29.4477 27.4477 29 28 29H38C38.5523 29 39 29.4477 39 30V38C39 38.5523 38.5523 39 38 39H28C27.4477 39 27 38.5523 27 38V30Z"/>
<path d="M27 42C27 41.4477 27.4477 41 28 41H38C38.5523 41 39 41.4477 39 42V50C39 50.5523 38.5523 51 38 51H28C27.4477 51 27 50.5523 27 50V42Z"/>
<path d="M41 6C41 5.44772 41.4477 5 42 5H52C52.5523 5 53 5.44772 53 6V14C53 14.5523 52.5523 15 52 15H42C41.4477 15 41 14.5523 41 14V6Z"/>
<path d="M41 18C41 17.4477 41.4477 17 42 17H52C52.5523 17 53 17.4477 53 18V26C53 26.5523 52.5523 27 52 27H42C41.4477 27 41 26.5523 41 26V18Z"/>
<path d="M41 30C41 29.4477 41.4477 29 42 29H52C52.5523 29 53 29.4477 53 30V38C53 38.5523 52.5523 39 52 39H42C41.4477 39 41 38.5523 41 38V30Z"/>
<path d="M41 42C41 41.4477 41.4477 41 42 41H52C52.5523 41 53 41.4477 53 42V50C53 50.5523 52.5523 51 52 51H42C41.4477 51 41 50.5523 41 50V42Z"/>
<path d="M55 6C55 5.44772 55.4477 5 56 5H66C66.5523 5 67 5.44772 67 6V14C67 14.5523 66.5523 15 66 15H56C55.4477 15 55 14.5523 55 14V6Z"/>
<path d="M55 18C55 17.4477 55.4477 17 56 17H66C66.5523 17 67 17.4477 67 18V26C67 26.5523 66.5523 27 66 27H56C55.4477 27 55 26.5523 55 26V18Z"/>
<path d="M55 30C55 29.4477 55.4477 29 56 29H66C66.5523 29 67 29.4477 67 30V38C67 38.5523 66.5523 39 66 39H56C55.4477 39 55 38.5523 55 38V30Z"/>
<path d="M55 42C55 41.4477 55.4477 41 56 41H66C66.5523 41 67 41.4477 67 42V50C67 50.5523 66.5523 51 66 51H56C55.4477 51 55 50.5523 55 50V42Z"/>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -0,0 +1,18 @@
<svg width="80" height="56" viewBox="0 0 80 56" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13 6C13 5.44772 13.4477 5 14 5H24C24.5523 5 25 5.44772 25 6V14C25 14.5523 24.5523 15 24 15H14C13.4477 15 13 14.5523 13 14V6Z" fill="#85A9FF"/>
<path d="M13 18C13 17.4477 13.4477 17 14 17H24C24.5523 17 25 17.4477 25 18V26C25 26.5523 24.5523 27 24 27H14C13.4477 27 13 26.5523 13 26V18Z" fill="#3370FF"/>
<path d="M13 30C13 29.4477 13.4477 29 14 29H24C24.5523 29 25 29.4477 25 30V38C25 38.5523 24.5523 39 24 39H14C13.4477 39 13 38.5523 13 38V30Z" fill="#85A9FF"/>
<path d="M13 42C13 41.4477 13.4477 41 14 41H24C24.5523 41 25 41.4477 25 42V50C25 50.5523 24.5523 51 24 51H14C13.4477 51 13 50.5523 13 50V42Z" fill="#85A9FF"/>
<path d="M27 6C27 5.44772 27.4477 5 28 5H38C38.5523 5 39 5.44772 39 6V14C39 14.5523 38.5523 15 38 15H28C27.4477 15 27 14.5523 27 14V6Z" fill="#D6E2FF"/>
<path d="M27 18C27 17.4477 27.4477 17 28 17H38C38.5523 17 39 17.4477 39 18V26C39 26.5523 38.5523 27 38 27H28C27.4477 27 27 26.5523 27 26V18Z" fill="#85A9FF"/>
<path d="M27 30C27 29.4477 27.4477 29 28 29H38C38.5523 29 39 29.4477 39 30V38C39 38.5523 38.5523 39 38 39H28C27.4477 39 27 38.5523 27 38V30Z" fill="#D6E2FF"/>
<path d="M27 42C27 41.4477 27.4477 41 28 41H38C38.5523 41 39 41.4477 39 42V50C39 50.5523 38.5523 51 38 51H28C27.4477 51 27 50.5523 27 50V42Z" fill="#3370FF"/>
<path d="M41 6C41 5.44772 41.4477 5 42 5H52C52.5523 5 53 5.44772 53 6V14C53 14.5523 52.5523 15 52 15H42C41.4477 15 41 14.5523 41 14V6Z" fill="#85A9FF"/>
<path d="M41 18C41 17.4477 41.4477 17 42 17H52C52.5523 17 53 17.4477 53 18V26C53 26.5523 52.5523 27 52 27H42C41.4477 27 41 26.5523 41 26V18Z" fill="#3370FF"/>
<path d="M41 30C41 29.4477 41.4477 29 42 29H52C52.5523 29 53 29.4477 53 30V38C53 38.5523 52.5523 39 52 39H42C41.4477 39 41 38.5523 41 38V30Z" fill="#85A9FF"/>
<path d="M41 42C41 41.4477 41.4477 41 42 41H52C52.5523 41 53 41.4477 53 42V50C53 50.5523 52.5523 51 52 51H42C41.4477 51 41 50.5523 41 50V42Z" fill="#D6E2FF"/>
<path d="M55 6C55 5.44772 55.4477 5 56 5H66C66.5523 5 67 5.44772 67 6V14C67 14.5523 66.5523 15 66 15H56C55.4477 15 55 14.5523 55 14V6Z" fill="#85A9FF"/>
<path d="M55 18C55 17.4477 55.4477 17 56 17H66C66.5523 17 67 17.4477 67 18V26C67 26.5523 66.5523 27 66 27H56C55.4477 27 55 26.5523 55 26V18Z" fill="#D6E2FF"/>
<path d="M55 30C55 29.4477 55.4477 29 56 29H66C66.5523 29 67 29.4477 67 30V38C67 38.5523 66.5523 39 66 39H56C55.4477 39 55 38.5523 55 38V30Z" fill="#85A9FF"/>
<path d="M55 42C55 41.4477 55.4477 41 56 41H66C66.5523 41 67 41.4477 67 42V50C67 50.5523 66.5523 51 66 51H56C55.4477 51 55 50.5523 55 50V42Z" fill="#85A9FF"/>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -354,7 +354,10 @@ const openOuterParamsSet = () => {
ElMessage.warning('请先保存当前页面')
return
}
outerParamsSetRef.value.optInit()
//
canvasSave(() => {
outerParamsSetRef.value.optInit()
})
}
const saveBatchChange = () => {

View File

@ -247,7 +247,10 @@ const openOuterParamsSet = () => {
ElMessage.warning('请先保存当前页面')
return
}
outerParamsSetRef.value.optInit()
//
canvasSave(() => {
outerParamsSetRef.value.optInit()
})
}
const multiplexingCanvasOpen = () => {

View File

@ -11,6 +11,7 @@ import { ElDivider } from 'element-plus-secondary'
import eventBus from '@/utils/eventBus'
import { getCurInfo } from '@/store/modules/data-visualization/common'
import { useEmitt } from '@/hooks/web/useEmitt'
import { XpackComponent } from '@/components/plugin'
const dvMainStore = dvMainStoreWithOut()
const copyStore = copyStoreWithOut()
const lockStore = lockStoreWithOut()
@ -245,6 +246,11 @@ const editQueryCriteria = () => {
<li @click="downComponent">下移一层</li>
<li @click="topComponent">置于顶层</li>
<li @click="bottomComponent">置于底层</li>
<xpack-component
:chart="curComponent"
is-screen
jsname="L2NvbXBvbmVudC90aHJlc2hvbGQtd2FybmluZy9FZGl0QmFySGFuZGxlcg=="
/>
<li
@click="categoryChange('hidden')"
v-show="

View File

@ -316,7 +316,8 @@ const boardMoveActive = computed(() => {
'table-normal',
'table-pivot',
'symbolic-map',
'heat-map'
'heat-map',
't-heatmap'
]
return element.value.isPlugin || CHARTS.includes(element.value.innerType)
})

View File

@ -679,6 +679,9 @@ import icon_single_line_outlined from '@/assets/svg/icon_single-line_outlined.sv
import icon_todo_outlined from '@/assets/svg/icon_todo_outlined.svg'
import icon_file_doc_colorful from '@/assets/svg/icon_file-doc_colorful.svg'
import icon_font from '@/assets/svg/icon_font.svg'
import tHeatmap from '@/assets/svg/t-heatmap.svg'
import tHeatmapDark from '@/assets/svg/t-heatmap-dark.svg'
import tHeatmapOrigin from '@/assets/svg/t-heatmap-origin.svg'
const iconMap = {
'401': _401,
icon_adjustment_outlined,
@ -1356,7 +1359,10 @@ const iconMap = {
calculate,
'icon_file-doc_colorful': icon_file_doc_colorful,
icon_font,
clock
clock,
't-heatmap': tHeatmap,
't-heatmap-dark': tHeatmapDark,
't-heatmap-origin': tHeatmapOrigin
}
const props = defineProps({

View File

@ -70,91 +70,171 @@
</el-col>
<el-col :span="16" class="preview-show">
<el-row v-if="state.curNodeId">
<el-row style="margin-top: 5px">
<el-row class="new-params-title"> 选择参数关联组件 </el-row>
<el-row class="new-params-filter" v-if="state.outerParamsInfo?.filterInfo?.length">
<div style="display: flex" class="inner-content">
<div style="flex: 1">联动组件</div>
<div style="width: 36px"></div>
<div style="flex: 1">联动组件字段</div>
<div style="width: 32px"></div>
<div style="width: 16px; margin-top: 2px">
<div class="expand-custom">
<el-icon @click="() => (state.filterExpand = !state.filterExpand)"
><CaretBottom v-show="state.filterExpand" />
<CaretRight v-show="!state.filterExpand" />
</el-icon>
</div>
</div>
<div style="flex: 1">查询组件</div>
<div style="flex: 1">关联条件</div>
</div>
<div style="width: 100%; max-height: 350px; overflow-y: auto">
<div class="outer-filter-content">
<div
style="display: flex; padding: 0 16px 8px"
v-for="(targetViewInfo, index) in state.outerParamsInfo.targetViewInfoList"
v-show="state.filterExpand"
style="display: flex"
class="inner-filter-content"
v-for="(baseFilter, index) in state.outerParamsInfo?.filterInfo"
:key="index"
>
<div style="flex: 1">
<div class="select-filed">
<el-select
v-model="targetViewInfo.targetViewId"
filterable
style="width: 100%"
size="small"
:placeholder="t('visualization.please_select')"
@change="viewInfoOnChange(targetViewInfo)"
>
<el-option
v-for="item in state.currentLinkPanelViewArray.filter(
curItem =>
!viewSelectedField.includes(curItem.id) ||
curItem.id === targetViewInfo.targetViewId
)"
:key="item.id"
:label="item.title"
:value="item.id"
>
<Icon
class-name="view-type-icon"
style="margin-right: 4px"
:name="item.type"
/>
<span style="font-size: 12px"> {{ item.title }}</span>
</el-option>
</el-select>
</div>
<div style="width: 16px"></div>
<div style="flex: 1; line-height: 32px">
<Icon style="margin-top: 4px" class-name="view-type-icon" name="filter" />
<span>{{ findFilterName(baseFilter.id) }}</span>
</div>
<el-icon class="link-icon-join">
<Icon style="width: 20px; height: 20px" name="dv-link-target" />
</el-icon>
<div style="flex: 1">
<div class="select-filed">
<el-select
v-model="targetViewInfo.targetFieldId"
filterable
:disabled="fieldIdDisabledCheck(targetViewInfo)"
style="width: 100%"
size="small"
:placeholder="t('visualization.please_select')"
<el-select
v-model="baseFilter.filterSelected"
filterable
style="width: 100%"
placeholder="请选择查询条件"
clearable
>
<el-option
v-for="item in baseFilter.propValue"
:key="item.id"
:label="item.name"
:value="item.id"
>
<span style="font-size: 12px"> {{ item.name }}</span>
</el-option>
</el-select>
</div>
</div>
</div>
</el-row>
<el-row class="new-params-ds" v-if="state.outerParamsInfo?.datasetInfo?.length">
<div style="display: flex" class="inner-content">
<div style="width: 16px; margin-top: 2px">
<div class="expand-custom">
<el-icon @click="() => (state.datasetExpand = !state.datasetExpand)"
><CaretBottom v-show="state.datasetExpand" />
<CaretRight v-show="!state.datasetExpand" />
</el-icon>
</div>
</div>
<div style="flex: 1">图表</div>
<div style="flex: 1">关联字段或参数</div>
</div>
<div class="outer-dataset-content">
<div
v-show="state.datasetExpand"
class="inner-dataset-content"
v-for="(baseDatasetInfo, index) in state.outerParamsInfo?.datasetInfo"
:key="index"
>
<div style="display: flex; width: 100%">
<div style="width: 16px; margin-top: 7px">
<div class="expand-custom">
<el-icon
@click="
() => (baseDatasetInfo.viewExpand = !baseDatasetInfo.viewExpand)
"
><CaretBottom v-show="baseDatasetInfo.viewExpand" />
<CaretRight v-show="!baseDatasetInfo.viewExpand" />
</el-icon>
</div>
</div>
<div style="flex: 1; display: flex; line-height: 32px">
<div style="width: 16px; margin-top: 2px; margin-right: 4px">
<el-icon>
<Icon name="icon_dataset" />
</el-icon>
</div>
<span>{{ baseDatasetInfo.name }}</span>
</div>
<div style="flex: 1">
<el-select
v-model="baseDatasetInfo.fieldIdSelected"
filterable
clearable
style="width: 100%"
placeholder="请选择"
>
<template #header>
<el-tabs
stretch
class="params-select--header"
v-model="baseDatasetInfo.activelist"
>
<el-tab-pane label="字段" name="dimensionList"></el-tab-pane>
<el-tab-pane label="参数" name="parameterList"></el-tab-pane>
</el-tabs>
</template>
<el-option
v-for="viewField in getFieldArray(targetViewInfo.targetViewId)"
:key="viewField.id"
:label="viewField.name"
:value="viewField.id"
v-for="item in findFields(
baseDatasetInfo.activelist,
baseDatasetInfo.datasetFields
)"
:key="item.attachId"
:label="item.name"
:value="item.attachId"
>
<Icon
style="width: 14px; height: 14px"
:name="`field_${fieldType[viewField.deType]}`"
:className="`field-icon-${fieldType[viewField.deType]}`"
:name="`field_${fieldType[item.deType]}`"
:className="`field-icon-${fieldType[item.deType]}`"
/>
<span style="font-size: 12px">{{ viewField.name }}</span>
<span style="font-size: 12px">{{ item.name }}</span>
</el-option>
</el-select>
</div>
</div>
<el-button class="m-del-icon-btn" text @click="deleteOuterParamsField(index)">
<el-icon size="20px">
<Icon name="icon_delete-trash_outlined" />
</el-icon>
</el-button>
<div class="ds-view-content" v-show="baseDatasetInfo.viewExpand">
<div style="display: flex; width: 100%; height: 22px">
<div class="ds-content-title">选择关联的图表</div>
<div class="custom-view-diver"></div>
<div>
<el-checkbox
style="margin-top: -4px"
v-model="baseDatasetInfo.checkAll"
:indeterminate="baseDatasetInfo.checkAllIsIndeterminate"
@change="batchSelectChange($event, baseDatasetInfo)"
>全选</el-checkbox
>
</div>
</div>
<div style="display: flex; width: 100%">
<div
style="display: flex; width: 50%; line-height: 32px"
v-for="viewInfo in baseDatasetInfo.datasetViews"
:key="viewInfo"
>
<div>
<el-checkbox
v-model="viewInfo.checked"
@change="datasetInfoChange(baseDatasetInfo)"
/>
</div>
<div>
<Icon
class-name="view-type-icon"
style="margin: 0 4px"
:name="viewInfo.chartType"
/>
</div>
<span style="font-size: 12px"> {{ viewInfo.chartName }}</span>
</div>
</div>
</div>
</div>
</div>
<el-row style="width: 100%; padding-left: 16px">
<el-button type="primary" icon="Plus" text @click="addOuterParamsField">
{{ t('visualization.add_param_link_field') }}
</el-button>
</el-row>
</el-row>
</el-row>
<div v-else class="empty">
@ -164,10 +244,8 @@
</el-row>
</el-row>
<el-row class="root-class">
<el-button size="small" @click="cancel()">{{ t('commons.cancel') }} </el-button>
<el-button type="primary" size="small" @click="save()"
>{{ t('commons.confirm') }}
</el-button>
<el-button @click="cancel()">{{ t('commons.cancel') }} </el-button>
<el-button type="primary" @click="save()">{{ t('commons.confirm') }} </el-button>
</el-row>
</el-row>
</el-dialog>
@ -177,12 +255,12 @@
import { ref, reactive, computed, nextTick } from 'vue'
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
import { storeToRefs } from 'pinia'
import { ElMessage } from 'element-plus-secondary'
import { ElCol, ElMessage } from 'element-plus-secondary'
import { useI18n } from '@/hooks/web/useI18n'
import { deepCopy } from '@/utils/utils'
import generateID from '@/utils/generateID'
import { queryWithVisualizationId, updateOuterParamsSet } from '@/api/visualization/outerParams'
import { viewDetailList } from '@/api/visualization/dataVisualization'
import { queryOuterParamsDsInfo, viewDetailList } from '@/api/visualization/dataVisualization'
import checkArrayRepeat from '@/utils/check'
import HandleMore from '@/components/handle-more/src/HandleMore.vue'
import { fieldType } from '@/utils/attr'
@ -196,6 +274,8 @@ const curEditDataId = ref(null)
const snapshotStore = snapshotStoreWithOut()
const state = reactive({
filterExpand: true,
datasetExpand: true,
loading: false,
outerParamsSetVisible: false,
optMenu: [
@ -219,6 +299,8 @@ const state = reactive({
checked: false,
outerParamsInfoArray: []
},
baseDatasetInfo: [],
baseFilterInfo: [],
outerParamsInfoArray: [],
mapOuterParamsInfoArray: {},
panelList: [],
@ -284,13 +366,28 @@ const getFieldArray = id => {
return state.viewIdFieldArrayMap[id]
}
const initParams = () => {
const initParams = async () => {
state.baseFilterInfo = []
state.baseDatasetInfo = []
//
componentData.value.forEach(componentItem => {
if (componentItem.component === 'VQuery') {
state.baseFilterInfo.push(componentItem)
}
})
//
await queryOuterParamsDsInfo(dvInfo.value.id).then(rsp => {
state.baseDatasetInfo = rsp.data
})
//
queryWithVisualizationId(dvInfo.value.id).then(rsp => {
state.outerParams = rsp.data
state.outerParamsInfoArray = state.outerParams?.outerParamsInfoArray
if (state.outerParamsInfoArray.length >= 1) {
state.outerParamsInfoArray.forEach(outerParamsInfo => {
const newBaseFilterInfo = deepCopy(state.baseFilterInfo)
const newBaseDatasetInfo = deepCopy(state.baseDatasetInfo)
paramsCheckedAdaptor(outerParamsInfo, newBaseFilterInfo, newBaseDatasetInfo)
state.mapOuterParamsInfoArray[outerParamsInfo.paramsInfoId] = outerParamsInfo
})
state.curNodeId = null
@ -300,22 +397,104 @@ const initParams = () => {
})
}
})
getPanelViewList(dvInfo.value.id)
}
const findFields = (type, datasetFields) => {
if (type === 'parameterList') {
return datasetFields.filter(field => field.attachId.indexOf('DE') > -1)
} else {
return datasetFields.filter(field => field.attachId.indexOf('DE') === -1)
}
}
const datasetInfoChange = datasetInfo => {
let viewCheckCount = 0
datasetInfo.datasetViews.forEach(dsView => {
if (dsView['checked']) {
viewCheckCount++
}
})
datasetInfo['checkAll'] = viewCheckCount === datasetInfo.datasetViews.length
datasetInfo['checkAllIsIndeterminate'] =
viewCheckCount > 0 && viewCheckCount < datasetInfo.datasetViews.length
}
const paramsCheckedAdaptor = (outerParamsInfo, newBaseFilterInfo, newBaseDatasetInfo) => {
const dsFieldIdSelected = {}
const viewMatchIds = []
outerParamsInfo.targetViewInfoList.forEach(targetViewInfo => {
viewMatchIds.push(targetViewInfo.targetViewId)
dsFieldIdSelected[targetViewInfo.targetDsId] =
targetViewInfo.targetFieldId === 'empty'
? targetViewInfo.targetViewId
: targetViewInfo.targetFieldId
})
if (newBaseDatasetInfo) {
newBaseDatasetInfo.forEach(datasetInfo => {
datasetInfo['fieldIdSelected'] = dsFieldIdSelected[datasetInfo.id]
datasetInfo['viewExpand'] = true
let viewCheckCount = 0
datasetInfo.datasetViews.forEach(dsView => {
if (viewMatchIds.includes(dsView.chartId)) {
dsView['checked'] = true
viewCheckCount++
} else {
dsView['checked'] = false
}
})
datasetInfo['checkAll'] = viewCheckCount === datasetInfo.datasetViews.length
datasetInfo['checkAllIsIndeterminate'] =
viewCheckCount > 0 && viewCheckCount < datasetInfo.datasetViews.length
if (datasetInfo['fieldIdSelected'] && datasetInfo['fieldIdSelected'].indexOf('DE') > -1) {
datasetInfo['activelist'] = 'parameterList'
} else {
datasetInfo['activelist'] = 'dimensionList'
}
})
}
if (newBaseFilterInfo) {
newBaseFilterInfo.forEach(filterInfo => {
filterInfo['filterSelected'] = dsFieldIdSelected[filterInfo.id]
})
}
outerParamsInfo['filterInfo'] = newBaseFilterInfo
outerParamsInfo['datasetInfo'] = newBaseDatasetInfo
}
const cancel = () => {
state.outerParamsSetVisible = false
}
const save = () => {
if (checkArrayRepeat(state.outerParams.outerParamsInfoArray, 'paramName')) {
ElMessage.warning({
message: t('visualization.repeat_params'),
showClose: true
const outerParamsCopy = deepCopy(state.outerParams)
outerParamsCopy.outerParamsInfoArray?.forEach(outerParamsInfo => {
outerParamsInfo.targetViewInfoList = []
outerParamsInfo.filterInfo?.forEach(baseFilterInfo => {
//
if (baseFilterInfo.filterSelected) {
outerParamsInfo.targetViewInfoList.push({
targetViewId: baseFilterInfo.filterSelected,
targetDsId: baseFilterInfo.id,
targetFieldId: 'empty'
})
}
})
return
}
updateOuterParamsSet(state.outerParams).then(() => {
outerParamsInfo.datasetInfo?.forEach(baseDatasetInfo => {
//
if (baseDatasetInfo.fieldIdSelected) {
baseDatasetInfo.datasetViews?.forEach(dsView => {
outerParamsInfo.targetViewInfoList.push({
targetViewId: dsView.chartId,
targetDsId: baseDatasetInfo.id,
targetFieldId: baseDatasetInfo.fieldIdSelected
})
})
}
})
})
updateOuterParamsSet(outerParamsCopy).then(() => {
ElMessage({
message: t('commons.save_success'),
type: 'success',
@ -395,6 +574,9 @@ const addOuterParamsInfo = () => {
state.outerParams.checked = true
const outerParamsInfo = deepCopy(state.defaultOuterParamsInfo)
outerParamsInfo['paramsInfoId'] = generateID()
const newBaseFilterInfo = deepCopy(state.baseFilterInfo)
const newBaseDatasetInfo = deepCopy(state.baseDatasetInfo)
paramsCheckedAdaptor(outerParamsInfo, newBaseFilterInfo, newBaseDatasetInfo)
state.outerParamsInfoArray.push(outerParamsInfo)
state.mapOuterParamsInfoArray[outerParamsInfo.paramsInfoId] = outerParamsInfo
curEditDataId.value = outerParamsInfo['paramsInfoId']
@ -410,12 +592,24 @@ const removeOuterParamsInfo = (node, data) => {
state.curNodeId = null
}
}
const batchSelectChange = (value, baseDatasetInfo) => {
// do change
baseDatasetInfo.datasetViews.forEach(viewInfo => {
viewInfo.checked = value
})
baseDatasetInfo.checkAll = value
baseDatasetInfo.checkAllIsIndeterminate = false
}
const optInit = () => {
state.outerParamsSetVisible = true
initParams()
}
const findFilterName = id => {
return dvMainStore.canvasViewInfo[id]?.title
}
defineExpose({
optInit
})
@ -488,12 +682,14 @@ defineExpose({
.preview-show {
border-left: 1px solid #e6e6e6;
background-size: 100% 100% !important;
height: 100%;
overflow-y: auto;
}
.view-type-icon {
color: var(--ed-color-primary);
width: 22px;
height: 16px;
height: 14px;
}
.custom-tree {
@ -529,8 +725,26 @@ defineExpose({
.inner-content {
width: 100%;
padding: 16px 16px 8px 16px;
font-size: 14px !important;
font-size: 14px;
}
.outer-filter-content {
width: 100%;
}
.outer-dataset-content {
width: 100%;
padding-left: 16px;
}
.inner-filter-content {
width: 100%;
margin-top: 12px;
}
.inner-dataset-content {
width: 100%;
margin-top: 12px;
}
.slot-class {
@ -644,4 +858,54 @@ defineExpose({
.params-class ::deep(.ed-dialog__body) {
padding: 10px 20px 20px;
}
.new-params-title {
height: 56px;
font-size: 14px;
font-weight: 500;
padding: 16px;
border-bottom: 1px solid rgba(31, 35, 41, 0.15);
}
.new-params-filter {
padding: 16px;
border-bottom: 1px solid rgba(31, 35, 41, 0.15);
}
.new-params-ds {
padding: 16px;
}
.expand-custom {
width: 16px;
height: 16px;
border-radius: 4px;
padding: 0px 1px;
color: rgba(100, 106, 115, 1);
&:hover {
background: rgba(31, 35, 41, 0.1);
cursor: pointer;
}
}
.ds-view-content {
width: calc(100% - 16px);
border-radius: 4px;
margin: 8px 16px 0 16px;
padding: 12px;
background: rgba(245, 246, 247, 1);
}
.ds-content-title {
font-size: 14px;
font-weight: 500;
color: rgba(100, 106, 115, 1);
}
.custom-view-diver {
width: 1px;
margin: 4px 4px;
height: 14px;
background: rgba(31, 35, 41, 0.15);
}
</style>

View File

@ -0,0 +1,647 @@
<template>
<el-dialog
class="params-class"
:append-to-body="true"
title="外部参数设置"
v-model="state.outerParamsSetVisible"
width="70vw"
top="10vh"
trigger="click"
>
<el-row style="height: 550px">
<el-row v-loading="state.loading">
<el-row class="preview">
<el-col :span="8" style="height: 100%; overflow-y: hidden">
<el-row class="tree-head">
<span class="head-text">参数列表</span>
<span class="head-filter">
<el-button type="primary" icon="Plus" text @click="addOuterParamsInfo"> </el-button>
</span>
</el-row>
<el-row class="tree-content">
<el-tree
class="custom-tree"
menu
ref="outerParamsInfoTree"
:data="state.outerParamsInfoArray"
node-key="id"
highlight-current
:props="state.treeProp"
@node-click="nodeClick"
>
<template #default="{ node, data }">
<span class="custom-tree-node">
<span>
<div @click.stop>
<span class="auth-span">
<el-checkbox
v-model="data.checked"
@change="sourceFieldCheckedChange(data)"
/>
</span>
</div>
</span>
<span :id="'paramName-' + data.paramsInfoId">
<el-input
v-if="curEditDataId === data.paramsInfoId"
v-model="data.paramName"
size="small"
:placeholder="$t('visualization.input_param_name')"
@blur="closeEdit"
/>
<span class="tree-select-field" v-else-if="data.paramName">
{{ data.paramName }}
</span>
<span class="tree-select-field" v-else> 未配置参数名 </span>
</span>
<span class="icon-more">
<handle-more
style="margin-right: 10px"
@handle-command="cmd => outerParamsOperation(cmd, node, data)"
:menu-list="state.optMenu"
icon-name="icon_more_outlined"
placement="bottom-start"
></handle-more>
</span>
</span>
</template>
</el-tree>
</el-row>
</el-col>
<el-col :span="16" class="preview-show">
<el-row v-if="state.curNodeId">
<el-row style="margin-top: 5px">
<div style="display: flex" class="inner-content">
<div style="flex: 1">联动组件</div>
<div style="width: 36px"></div>
<div style="flex: 1">联动组件字段</div>
<div style="width: 32px"></div>
</div>
<div style="width: 100%; max-height: 350px; overflow-y: auto">
<div
style="display: flex; padding: 0 16px 8px"
v-for="(targetViewInfo, index) in state.outerParamsInfo.targetViewInfoList"
:key="index"
>
<div style="flex: 1">
<div class="select-filed">
<el-select
v-model="targetViewInfo.targetViewId"
filterable
style="width: 100%"
size="small"
:placeholder="t('visualization.please_select')"
@change="viewInfoOnChange(targetViewInfo)"
>
<el-option
v-for="item in state.currentLinkPanelViewArray.filter(
curItem =>
!viewSelectedField.includes(curItem.id) ||
curItem.id === targetViewInfo.targetViewId
)"
:key="item.id"
:label="item.title"
:value="item.id"
>
<Icon
class-name="view-type-icon"
style="margin-right: 4px"
:name="item.type"
/>
<span style="font-size: 12px"> {{ item.title }}</span>
</el-option>
</el-select>
</div>
</div>
<el-icon class="link-icon-join">
<Icon style="width: 20px; height: 20px" name="dv-link-target" />
</el-icon>
<div style="flex: 1">
<div class="select-filed">
<el-select
v-model="targetViewInfo.targetFieldId"
filterable
:disabled="fieldIdDisabledCheck(targetViewInfo)"
style="width: 100%"
size="small"
:placeholder="t('visualization.please_select')"
>
<el-option
v-for="viewField in getFieldArray(targetViewInfo.targetViewId)"
:key="viewField.id"
:label="viewField.name"
:value="viewField.id"
>
<Icon
style="width: 14px; height: 14px"
:name="`field_${fieldType[viewField.deType]}`"
:className="`field-icon-${fieldType[viewField.deType]}`"
/>
<span style="font-size: 12px">{{ viewField.name }}</span>
</el-option>
</el-select>
</div>
</div>
<el-button class="m-del-icon-btn" text @click="deleteOuterParamsField(index)">
<el-icon size="20px">
<Icon name="icon_delete-trash_outlined" />
</el-icon>
</el-button>
</div>
</div>
<el-row style="width: 100%; padding-left: 16px">
<el-button type="primary" icon="Plus" text @click="addOuterParamsField">
{{ t('visualization.add_param_link_field') }}
</el-button>
</el-row>
</el-row>
</el-row>
<div v-else class="empty">
<empty-background description="请配置参数" img-type="noneWhite" />
</div>
</el-col>
</el-row>
</el-row>
<el-row class="root-class">
<el-button size="small" @click="cancel()">{{ t('commons.cancel') }} </el-button>
<el-button type="primary" size="small" @click="save()"
>{{ t('commons.confirm') }}
</el-button>
</el-row>
</el-row>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, reactive, computed, nextTick } from 'vue'
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
import { storeToRefs } from 'pinia'
import { ElMessage } from 'element-plus-secondary'
import { useI18n } from '@/hooks/web/useI18n'
import { deepCopy } from '@/utils/utils'
import generateID from '@/utils/generateID'
import { queryWithVisualizationId, updateOuterParamsSet } from '@/api/visualization/outerParams'
import { viewDetailList } from '@/api/visualization/dataVisualization'
import checkArrayRepeat from '@/utils/check'
import HandleMore from '@/components/handle-more/src/HandleMore.vue'
import { fieldType } from '@/utils/attr'
import EmptyBackground from '@/components/empty-background/src/EmptyBackground.vue'
import { snapshotStoreWithOut } from '@/store/modules/data-visualization/snapshot'
const dvMainStore = dvMainStoreWithOut()
const { dvInfo, componentData } = storeToRefs(dvMainStore)
const outerParamsInfoTree = ref(null)
const { t } = useI18n()
const curEditDataId = ref(null)
const snapshotStore = snapshotStoreWithOut()
const state = reactive({
loading: false,
outerParamsSetVisible: false,
optMenu: [
{
label: '重命名',
svgName: 'edit',
command: 'rename'
},
{
label: '删除',
svgName: 'delete',
command: 'delete'
}
],
treeProp: {
id: 'paramsInfoId',
label: 'paramName',
children: 'children'
},
outerParams: {
checked: false,
outerParamsInfoArray: []
},
outerParamsInfoArray: [],
mapOuterParamsInfoArray: {},
panelList: [],
curNodeId: null,
outerParamsInfo: {
content: '',
linkType: '',
targetViewInfoList: [],
paramsInfoId: null
},
currentFiledTreeNode: null,
defaultOuterParamsInfo: {
paramName: '',
checked: true,
targetViewInfoList: []
},
defaultTargetViewInfo: {
targetViewId: null,
targetFieldId: null
},
currentLinkPanelViewArray: [],
viewIdFieldArrayMap: {},
widgetSubjectsTrans: {
timeYearWidget: '年份过滤组件',
timeMonthWidget: '年月过滤组件',
timeDateWidget: '日期过滤组件',
timeDateRangeWidget: '日期范围过滤组件',
textSelectWidget: '文本下拉过滤组件',
textSelectGridWidget: '文本列表过滤组件',
textInputWidget: '文本搜索过滤组件',
textSelectTreeWidget: '下拉树过滤组件',
numberSelectWidget: '数字下拉过滤组件',
numberSelectGridWidget: '数字列表过滤组件',
numberRangeWidget: '数值区间过滤组件'
}
})
const viewSelectedField = computed(() =>
state.outerParamsInfo?.targetViewInfoList?.map(targetViewInfo => targetViewInfo.targetViewId)
)
const closeEdit = () => {
curEditDataId.value = null
}
const outerParamsOperation = (cmd, node, data) => {
if (cmd === 'rename') {
curEditDataId.value = data.paramsInfoId
} else if (cmd === 'delete') {
removeOuterParamsInfo(node, data)
}
}
const fieldIdDisabledCheck = targetViewInfo => {
return (
state.viewIdFieldArrayMap[targetViewInfo.targetViewId] &&
state.viewIdFieldArrayMap[targetViewInfo.targetViewId].length === 1 &&
state.viewIdFieldArrayMap[targetViewInfo.targetViewId][0].id === 'empty'
)
}
const getFieldArray = id => {
return state.viewIdFieldArrayMap[id]
}
const initParams = () => {
//
queryWithVisualizationId(dvInfo.value.id).then(rsp => {
state.outerParams = rsp.data
state.outerParamsInfoArray = state.outerParams?.outerParamsInfoArray
if (state.outerParamsInfoArray.length >= 1) {
state.outerParamsInfoArray.forEach(outerParamsInfo => {
state.mapOuterParamsInfoArray[outerParamsInfo.paramsInfoId] = outerParamsInfo
})
state.curNodeId = null
nextTick(() => {
// outerParamsInfoTree.value.setCurrentKey(firstNode.paramsInfoId)
// nodeClick(firstNode)
})
}
})
getPanelViewList(dvInfo.value.id)
}
const cancel = () => {
state.outerParamsSetVisible = false
}
const save = () => {
if (checkArrayRepeat(state.outerParams.outerParamsInfoArray, 'paramName')) {
ElMessage.warning({
message: t('visualization.repeat_params'),
showClose: true
})
return
}
updateOuterParamsSet(state.outerParams).then(() => {
ElMessage({
message: t('commons.save_success'),
type: 'success',
showClose: true
})
snapshotStore.recordSnapshotCache('renderChart')
cancel()
})
}
const nodeClick = data => {
state.outerParamsInfo = state.mapOuterParamsInfoArray[data.paramsInfoId]
state.curNodeId = data.paramsInfoId
}
//
const getPanelViewList = dvId => {
viewDetailList(dvId).then(rsp => {
state.viewIdFieldArrayMap = {}
state.currentLinkPanelViewArray = rsp.data
if (state.currentLinkPanelViewArray) {
state.currentLinkPanelViewArray.forEach(view => {
state.viewIdFieldArrayMap[view.id] = view.tableFields
})
}
//
componentData.value.forEach(componentItem => {
if (componentItem.component === 'VQuery') {
componentItem.propValue.forEach(filterItem => {
state.currentLinkPanelViewArray.push({
id: filterItem.id,
type: 'filter',
name: filterItem.name,
title: filterItem.name
})
state.viewIdFieldArrayMap[filterItem.id] = [
{ id: 'empty', name: t('visualization.filter_no_select') }
]
})
}
})
})
}
const addOuterParamsField = () => {
state.outerParamsInfo.targetViewInfoList.push({
targetViewId: '',
targetFieldId: ''
})
}
const deleteOuterParamsField = index => {
state.outerParamsInfo.targetViewInfoList.splice(index, 1)
}
const viewInfoOnChange = targetViewInfo => {
if (
state.viewIdFieldArrayMap[targetViewInfo.targetViewId] &&
state.viewIdFieldArrayMap[targetViewInfo.targetViewId].length === 1 &&
state.viewIdFieldArrayMap[targetViewInfo.targetViewId][0].id === 'empty'
) {
targetViewInfo.targetFieldId = 'empty'
} else {
targetViewInfo.targetFieldId = null
}
}
const sourceFieldCheckedChange = data => {
if (data.checked) {
state.outerParams.checked = true
}
nextTick(() => {
outerParamsInfoTree.value.setCurrentKey(data.paramsInfoId)
nodeClick(data)
})
}
const addOuterParamsInfo = () => {
state.outerParams.checked = true
const outerParamsInfo = deepCopy(state.defaultOuterParamsInfo)
outerParamsInfo['paramsInfoId'] = generateID()
state.outerParamsInfoArray.push(outerParamsInfo)
state.mapOuterParamsInfoArray[outerParamsInfo.paramsInfoId] = outerParamsInfo
curEditDataId.value = outerParamsInfo['paramsInfoId']
}
const removeOuterParamsInfo = (node, data) => {
const parent = node.parent
const children = parent.data.children || parent.data
const index = children.findIndex(d => d.paramsInfoId === data.paramsInfoId)
children.splice(index, 1)
if (data.paramsInfoId === state.outerParamsInfo.paramsInfoId) {
delete state.mapOuterParamsInfoArray[data.paramsInfoId]
state.curNodeId = null
}
}
const optInit = () => {
state.outerParamsSetVisible = true
initParams()
}
defineExpose({
optInit
})
</script>
<style scoped lang="less">
.root-class {
margin: 15px 0px 5px;
justify-content: right;
}
.preview {
margin-top: 5px;
border: 1px solid #e6e6e6;
border-radius: 4px;
height: 470px !important;
overflow: hidden;
background-size: 100% 100% !important;
}
.tree-head {
height: 40px;
line-height: 40px;
font-size: 12px;
color: #3d4d66;
.head-text {
margin-left: 16px;
font-weight: 500;
font-size: 14px;
color: #1f2329;
}
.head-filter {
flex: 1;
text-align: right;
margin-right: 16px;
font-weight: 400;
font-size: 12px;
color: #646a73;
}
}
:deep(.ed-row) {
width: 100%;
}
.m-del-icon-btn {
color: #646a73;
margin-top: 4px;
margin-left: 4px;
&:hover {
background: rgba(31, 35, 41, 0.1) !important;
}
&:focus {
background: rgba(31, 35, 41, 0.1) !important;
}
&:active {
background: rgba(31, 35, 41, 0.2) !important;
}
}
.empty {
width: 100%;
height: 100%;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}
.preview-show {
border-left: 1px solid #e6e6e6;
background-size: 100% 100% !important;
}
.view-type-icon {
color: var(--ed-color-primary);
width: 22px;
height: 16px;
}
.custom-tree {
height: 100%;
width: 100%;
overflow-y: auto;
}
.custom-tree-node {
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 14px;
.icon-more {
margin-left: auto;
visibility: hidden;
}
&:hover .icon-more {
margin-left: auto;
visibility: visible;
}
}
.link-icon-join {
font-size: 20px;
margin-top: 7px;
margin-left: 8px;
margin-right: 8px;
}
.inner-content {
width: 100%;
padding: 16px 16px 8px 16px;
font-size: 14px !important;
}
.slot-class {
color: white;
}
.bottom {
margin-top: 15px;
text-align: center;
}
.ellip {
/*width: 100%;*/
margin-left: 10px;
margin-right: 10px;
overflow: hidden; /*超出部分隐藏*/
white-space: nowrap; /*不换行*/
text-overflow: ellipsis; /*超出部分文字以...显示*/
text-align: center;
background-color: #f7f8fa;
color: #3d4d66;
font-size: 12px;
line-height: 24px;
height: 24px;
border-radius: 3px;
}
.select-filed {
/*width: 100%;*/
overflow: hidden; /*超出部分隐藏*/
white-space: nowrap; /*不换行*/
text-overflow: ellipsis; /*超出部分文字以...显示*/
color: #3d4d66;
font-size: 12px;
line-height: 35px;
height: 35px;
border-radius: 3px;
}
:deep(.ed-popover) {
height: 200px;
overflow: auto;
}
.custom-position {
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 14px;
flex-flow: row nowrap;
color: #9ea6b2;
}
.tree-style {
padding: 10px 15px;
height: 100%;
overflow-y: auto;
}
:deep(.vue-treeselect__control) {
height: 28px;
}
:deep(.vue-treeselect__single-value) {
color: #606266;
line-height: 28px !important;
}
.auth-span {
float: right;
width: 40px;
margin-right: 5px;
}
.tree-content {
height: calc(100% - 70px);
overflow-y: auto;
}
.tree-bottom {
margin-top: 7px;
text-align: center;
}
:deep(.vue-treeselect__placeholder) {
line-height: 28px;
}
:deep(.ed-tree--highlight-current .ed-tree-node.is-current > .ed-tree-node__content) {
background-color: rgba(51, 112, 255, 0.1) !important;
}
.tree-content ::deep(.ed-input__inner) {
background: transparent;
border: 0px !important;
}
.params-class ::deep(.ed-dialog__title) {
font-size: 14px;
}
.params-class ::deep(.ed-dialog__headerbtn) {
z-index: 2;
}
.params-class ::deep(.ed-dialog__header) {
padding: 20px 20px 0;
}
.params-class ::deep(.ed-dialog__body) {
padding: 10px 20px 20px;
}
</style>

View File

@ -347,13 +347,15 @@ const drop = e => {
checkedFieldsMap[ele.id] = componentInfo.id
}
})
// URL
const displayType = componentInfo.deType === 7 ? 0 : componentInfo.deType
list.value.push({
...infoFormat(componentInfo),
auto: true,
optionValueSource: 1,
checkedFields,
checkedFieldsMap,
displayType: `${componentInfo.deType}`
displayType
})
})
element.value.propValue = [...list.value]

View File

@ -330,6 +330,9 @@ const setType = () => {
if (!(field?.deType === 1 && curComponent.value.displayType === '7')) {
curComponent.value.displayType = `${[3, 4].includes(field?.deType) ? 2 : field?.deType}`
}
if (field?.deType === 7) {
curComponent.value.displayType = '0'
}
if (
displayType !== curComponent.value.displayType &&
!([3, 4].includes(+displayType) && +curComponent.value.displayType === 2)
@ -1848,7 +1851,8 @@ defineExpose({
v-for="ele in curComponent.dataset.fields.filter(
ele =>
ele.deType === +curComponent.displayType ||
([3, 4].includes(ele.deType) && +curComponent.displayType === 2)
([3, 4].includes(ele.deType) && +curComponent.displayType === 2) ||
(ele.deType === 7 && +curComponent.displayType === 0)
)"
:key="ele.id"
:label="ele.name"
@ -1899,7 +1903,8 @@ defineExpose({
v-for="ele in curComponent.dataset.fields.filter(
ele =>
ele.deType === +curComponent.displayType ||
([3, 4].includes(ele.deType) && +curComponent.displayType === 2)
([3, 4].includes(ele.deType) && +curComponent.displayType === 2) ||
(ele.deType === 7 && +curComponent.displayType === 0)
)"
:key="ele.id"
:label="ele.name"

View File

@ -146,10 +146,18 @@ onMounted(() => {
</el-menu>
<div class="operate-setting" v-if="!desktop">
<XpackComponent jsname="c3dpdGNoZXI=" />
<el-icon style="margin: 0 10px" class="ai-icon copilot-icon" v-if="!showOverlayCopilot">
<el-icon
style="margin: 0 10px"
class="ai-icon copilot-icon"
v-if="!showOverlayCopilot && appearanceStore.getShowCopilot"
>
<Icon name="copilot" @click="handleCopilotClick" />
</el-icon>
<Copilot @confirm="copilotConfirm" v-if="showOverlayCopilot" class="copilot-icon-tips" />
<Copilot
@confirm="copilotConfirm"
v-if="showOverlayCopilot && appearanceStore.getShowCopilot"
class="copilot-icon-tips"
/>
<el-icon
style="margin: 0 10px"
@ -181,7 +189,7 @@ onMounted(() => {
:base-url="aiBaseUrl"
></ai-component>
<div v-if="showOverlay && appearanceStore.getShowAi" class="overlay"></div>
<div v-if="showOverlayCopilot" class="overlay"></div>
<div v-if="showOverlayCopilot && appearanceStore.getShowCopilot" class="overlay"></div>
</div>
</el-header>
<ExportExcel ref="ExportExcelRef"></ExportExcel>

View File

@ -1116,6 +1116,7 @@ export default {
table_column_fixed: '固定列宽',
table_column_custom: '自定义',
chart_table_pivot: '透视表',
chart_table_heatmap: '热力图',
table_pivot_row: '数据行',
field_error_tips:
'该字段所对应的数据集原始字段发生变更包括维度指标字段类型字段被删除等建议重新编辑',
@ -2787,6 +2788,8 @@ export default {
name: '告警名称',
grid_title: '告警管理',
grid: '告警列表',
record: '告警记录'
record: '告警记录',
module_name: '阈值告警',
setting: '阈值告警设置'
}
}

View File

@ -68,6 +68,8 @@ declare interface Chart {
flowMapStartName?: Axis[]
flowMapEndName?: Axis[]
showPosition: string
extColor: Axis[]
}
declare type CustomAttr = DeepPartial<ChartAttr> | JSONString<DeepPartial<ChartAttr>>
declare type CustomStyle = DeepPartial<ChartStyle> | JSONString<DeepPartial<ChartStyle>>

View File

@ -57,7 +57,7 @@ declare type AxisType =
| 'area'
| 'flowMapStartName'
| 'flowMapEndName'
| 'flowMapColor'
| 'extColor'
/**
* 轴配置
*/

View File

@ -12,8 +12,11 @@ interface AppearanceState {
customColor?: string
navigateBg?: string
navigate?: string
mobileLogin?: string
mobileLoginBg?: string
help?: string
showAi?: string
showCopilot?: string
showDoc?: string
showAbout?: string
bg?: string
@ -36,9 +39,12 @@ export const useAppearanceStore = defineStore('appearanceStore', {
customColor: '',
navigateBg: '',
navigate: '',
mobileLogin: '',
mobileLoginBg: '',
help: '',
showDoc: '0',
showAi: '0',
showCopilot: '0',
showAbout: '0',
bg: '',
login: '',
@ -60,6 +66,18 @@ export const useAppearanceStore = defineStore('appearanceStore', {
}
return null
},
getMobileLogin(): string {
if (this.mobileLogin) {
return baseUrl + this.mobileLogin
}
return null
},
getMobileLoginBg(): string {
if (this.mobileLoginBg) {
return baseUrl + this.mobileLoginBg
}
return null
},
getHelp(): string {
return this.help
},
@ -117,6 +135,9 @@ export const useAppearanceStore = defineStore('appearanceStore', {
getShowAi(): boolean {
return isBtnShow(this.showAi)
},
getShowCopilot(): boolean {
return isBtnShow(this.showCopilot)
},
getShowDoc(): boolean {
return isBtnShow(this.showDoc)
},
@ -128,6 +149,12 @@ export const useAppearanceStore = defineStore('appearanceStore', {
setNavigate(data: string) {
this.navigate = data
},
setMobileLogin(data: string) {
this.mobileLogin = data
},
setMobileLoginBg(data: string) {
this.mobileLoginBg = data
},
setHelp(data: string) {
this.help = data
},
@ -177,8 +204,11 @@ export const useAppearanceStore = defineStore('appearanceStore', {
return
}
this.navigate = data.navigate
this.mobileLogin = data.mobileLogin
this.mobileLoginBg = data.mobileLoginBg
this.help = data.help
this.showAi = data.showAi
this.showCopilot = data.showCopilot
this.showDoc = data.showDoc
this.showAbout = data.showAbout
this.navigateBg = data.navigateBg

View File

@ -81,7 +81,10 @@ const setLicense = lic => {
dynamicCardClass.value = 'about-card-medium'
}
}
const removeDistributeModule = () => {
const key = 'xpack-model-distributed'
localStorage.removeItem(key)
}
const importLic = file => {
const reader = new FileReader()
reader.onload = function (e) {
@ -93,6 +96,7 @@ const importLic = file => {
reader.readAsText(file)
}
const validateHandler = (param, success) => {
removeDistributeModule()
validateApi(param).then(success)
}
const getLicense = result => {

View File

@ -402,7 +402,7 @@ onMounted(() => {
</el-dropdown-item>-->
<el-dropdown-item
@click.prevent
v-if="!item.chartId && chart.type !== 'table-info' && item.summary !== ''"
v-if="chart.type !== 'table-info' && item.summary !== ''"
>
<el-dropdown
:effect="themes"

View File

@ -32,14 +32,42 @@ const { compareItem, chart } = toRefs(props)
const state = reactive({
fieldList: [],
compareList: []
compareList: [],
dateFormatter: 'y_M_d'
})
const dateFormatterList = [
{ name: '年', value: 'y' },
{ name: '年月', value: 'y_M' },
{ name: '年月日', value: 'y_M_d' }
]
const changeDateFormatter = () => {
const checkedField = state.fieldList.filter(ele => ele.id === compareItem.value.compareCalc.field)
if (checkedField && checkedField.length > 0) {
checkedField[0].dateStyle = state.dateFormatter
if (!compareItem.value.compareCalc.custom) {
compareItem.value.compareCalc.custom = { timeType: 'y_M_d' }
}
compareItem.value.compareCalc.custom.timeType = state.dateFormatter
}
initCompareType()
}
const initDateFormatter = () => {
const timeType = compareItem.value.compareCalc.custom?.timeType
if (isIndicator.value && timeType) {
state.dateFormatter = timeType
changeDateFormatter()
}
}
watch(
() => props.chart,
() => {
initFieldList()
initCompareType()
initDateFormatter()
},
{ deep: true }
)
@ -109,15 +137,6 @@ const initCompareType = () => {
} else {
state.compareList = []
}
if (isIndicator.value) {
state.compareList = [
{ name: 'day_mom', value: 'day_mom' },
{ name: 'month_mom', value: 'month_mom' },
{ name: 'year_mom', value: 'year_mom' },
{ name: 'month_yoy', value: 'month_yoy' },
{ name: 'year_yoy', value: 'year_yoy' }
]
}
//
if (
(!compareItem.value.compareCalc.type ||
@ -136,9 +155,9 @@ const fieldFormatter = field => {
return field.name + '(' + t('chart.' + field.dateStyle) + ')'
}
}
initFieldList()
initCompareType()
initDateFormatter()
</script>
<template>
@ -158,12 +177,25 @@ initCompareType()
/>
</el-select>
</el-form-item>
<el-form-item v-if="isIndicator" :label="t('chart.datePattern')">
<el-select
v-model="state.dateFormatter"
:placeholder="t('chart.date_format')"
@change="changeDateFormatter"
>
<el-option
v-for="field in dateFormatterList"
:key="field.value"
:label="field.name"
:value="field.value"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('chart.compare_type')">
<el-radio-group v-model="compareItem.compareCalc.type">
<el-radio v-for="radio in state.compareList" :key="radio.value" :label="radio.value">{{
t('chart.' + radio.value)
}}</el-radio>
<el-radio v-for="radio in state.compareList" :key="radio.value" :label="radio.value"
>{{ t('chart.' + radio.value) }}
</el-radio>
</el-radio-group>
</el-form-item>
@ -196,18 +228,22 @@ initCompareType()
.ed-form-item {
margin-bottom: 10px !important;
}
.compare-form :deep(.ed-form-item__label) {
font-size: 12px !important;
font-weight: 400 !important;
padding-top: 8px !important;
}
.compare-form :deep(.ed-radio__label) {
font-size: 12px !important;
font-weight: 400 !important;
}
.el-select-dropdown__item :deep(span) {
font-size: 12px !important;
}
.exp-style {
color: #c0c4cc;
font-size: 12px;

View File

@ -101,7 +101,7 @@ init()
<style lang="less" scoped>
.drag-list {
height: 100%;
height: 50vh;
}
.item-dimension {

View File

@ -20,6 +20,7 @@ import { storeToRefs } from 'pinia'
import { BASE_VIEW_CONFIG } from '../util/chart'
import { cloneDeep, defaultsDeep } from 'lodash-es'
import BubbleAnimateCfg from '@/views/chart/components/editor/editor-senior/components/BubbleAnimateCfg.vue'
import { XpackComponent } from '@/components/plugin'
const dvMainStore = dvMainStoreWithOut()
const { nowPanelTrackInfo, nowPanelJumpInfo, dvInfo, componentData } = storeToRefs(dvMainStore)
@ -126,7 +127,6 @@ const onMapMappingChange = val => {
}
const onBubbleAnimateChange = val => {
console.log(val)
emit('onBubbleAnimateChange', val)
}
@ -282,6 +282,13 @@ const isDataEaseBi = computed(() => appStore.getIsDataEaseBi)
/>
</collapse-switch-item>
<xpack-component
v-if="chart.id"
:chart="chart"
:themes="themes"
jsname="L2NvbXBvbmVudC90aHJlc2hvbGQtd2FybmluZy9TZW5pb3JIYW5kbGVy"
/>
<collapse-switch-item
v-if="showProperties('linkage')"
:themes="themes"

View File

@ -144,7 +144,7 @@ const getTimeValue = dynamicTimeSetting => {
label: '年初',
value: 'yearBeginning'
}
].find(ele => ele.value === relativeToCurrent).label
].find(ele => ele.value === relativeToCurrent)?.label
return timeValue
}
timeValue = `${timeNum}${relativeToCurrentTypeMap[relativeToCurrentType]}${

View File

@ -413,6 +413,8 @@ const dimensionItemRemove = item => {
view.value.flowMapStartName.splice(item.index, 1)
} else if (item.removeType === 'flowMapEndName') {
view.value.flowMapEndName.splice(item.index, 1)
} else if (item.removeType === 'extColor') {
view.value.extColor.splice(item.index, 1)
}
}
@ -524,7 +526,12 @@ const onCustomFlowMapEndNameSort = item => {
customSortAxis.value = 'flowMapEndName'
customSort()
}
const onCustomExtColorSort = item => {
recordSnapshotInfo('render')
state.customSortField = view.value.extColor[item.index]
customSortAxis.value = 'extColor'
customSort()
}
const onMove = e => {
recordSnapshotInfo('calcData')
state.moveId = e.draggedContext.element.id
@ -798,6 +805,10 @@ const addFlowMapEndName = e => {
addAxis(e, 'flowMapEndName')
}
const addExtColor = e => {
addAxis(e, 'extColor')
}
const onAxisChange = (e, axis: AxisType) => {
if (e.removed) {
const { element } = e.removed
@ -844,7 +855,6 @@ const onAreaChange = val => {
const onTypeChange = (render, type) => {
const viewConf = getViewConfig(type)
console.log(view.value)
if (viewConf.isPlugin) {
view.value.plugin = {
isPlugin: true,
@ -1110,6 +1120,11 @@ const onChangeFlowMapPointForm = val => {
renderChart(view.value)
}
const onChangExtColorForm = val => {
view.value.extColor = val
renderChart(view.value)
}
const showRename = val => {
recordSnapshotInfo('render')
state.itemForm = JSON.parse(JSON.stringify(val))
@ -1135,6 +1150,7 @@ const removeItems = (
| 'drillFields'
| 'flowMapStartName'
| 'flowMapEndName'
| 'extColor'
) => {
recordSnapshotInfo('calcData')
let axis = []
@ -1170,6 +1186,9 @@ const removeItems = (
case 'flowMapEndName':
axis = view.value.flowMapEndName?.splice(0)
break
case 'extColor':
axis = view.value.extColor?.splice(0)
break
}
axis?.length && emitter.emit('removeAxis', { axisType: _type, axis, editType: 'remove' })
}
@ -1223,6 +1242,11 @@ const saveRename = ref => {
axis = view.value.flowMapEndName[index]
view.value.flowMapEndName[index].chartShowName = chartShowName
break
case 'extColor':
axisType = 'extColor'
axis = view.value.extColor[index]
view.value.extColor[index].chartShowName = chartShowName
break
default:
break
}
@ -2131,6 +2155,64 @@ const deleteChartFieldItem = id => {
</div>
</el-row>
<el-row v-if="showAxis('extColor')" class="padding-lr drag-data">
<div class="form-draggable-title">
<span>
{{ chartViewInstance.axisConfig.extColor.name }}
</span>
<el-tooltip
:effect="toolTip"
placement="top"
:content="t('common.delete')"
>
<el-icon
class="remove-icon"
:class="{ 'remove-icon--dark': themes === 'dark' }"
size="14px"
@click="removeItems('extColor')"
>
<Icon class-name="inner-class" name="icon_delete-trash_outlined" />
</el-icon>
</el-tooltip>
</div>
<div
class="qw"
@drop="$event => drop($event, 'extColor')"
@dragenter="dragEnter"
@dragover="$event => dragOver($event)"
>
<draggable
:list="view.extColor"
:move="onMove"
item-key="id"
group="drag"
animation="300"
class="drag-block-style"
:class="{ dark: themes === 'dark' }"
@add="addExtColor"
@change="e => onAxisChange(e, 'extColor')"
>
<template #item="{ element, index }">
<dimension-item
:dimension-data="state.dimension"
:quota-data="state.quota"
:chart="view"
:item="element"
:index="index"
:themes="props.themes"
type="extColor"
@onDimensionItemChange="dimensionItemChange"
@onDimensionItemRemove="dimensionItemRemove"
@onNameEdit="showRename"
@onCustomSort="onCustomExtColorSort"
@valueFormatter="valueFormatter"
/>
</template>
</draggable>
<drag-placeholder :themes="themes" :drag-list="view.extColor" />
</div>
</el-row>
<template v-if="view.type !== 'bar-range'">
<!--yAxis-->
<el-row v-if="showAxis('yAxis')" class="padding-lr drag-data">
@ -4578,7 +4660,7 @@ span {
}
.custom_sort_dialog {
max-height: calc(100vh - 120px);
max-height: calc(100vh - 100px);
min-height: 152px;
display: flex;

View File

@ -1183,6 +1183,13 @@ export const CHART_TYPE_CONFIGS = [
value: 'table-pivot',
title: t('chart.chart_table_pivot'),
icon: 'table-pivot'
},
{
render: 'antv',
category: 'table',
value: 't-heatmap',
title: t('chart.chart_table_heatmap'),
icon: 't-heatmap'
}
]
},

View File

@ -0,0 +1,332 @@
import {
G2PlotChartView,
G2PlotDrawOptions
} from '@/views/chart/components/js/panel/types/impl/g2plot'
import type { Heatmap, HeatmapOptions } from '@antv/g2plot/esm/plots/heatmap'
import { flow, hexColorToRGBA, parseJson } from '@/views/chart/components/js/util'
import { useI18n } from '@/hooks/web/useI18n'
import { deepCopy } from '@/utils/utils'
import { cloneDeep } from 'lodash-es'
import {
getPadding,
getXAxis,
getYAxis
} from '@/views/chart/components/js/panel/common/common_antv'
import { valueFormatter } from '@/views/chart/components/js/formatter'
const { t } = useI18n()
const DEFAULT_DATA = []
/**
* 热力图
*/
export class TableHeatmap extends G2PlotChartView<HeatmapOptions, Heatmap> {
properties: EditorProperty[] = [
'basic-style-selector',
'background-overall-component',
'label-selector',
'legend-selector',
'x-axis-selector',
'y-axis-selector',
'title-selector',
'tooltip-selector',
'jump-set',
'linkage'
]
propertyInner: EditorPropertyInner = {
'background-overall-component': ['all'],
'basic-style-selector': ['colors'],
'label-selector': ['fontSize', 'color'],
'x-axis-selector': ['name', 'color', 'fontSize', 'position', 'axisLabel', 'axisLine'],
'y-axis-selector': ['name', 'color', 'fontSize', 'position', 'axisLabel', 'axisLine'],
'title-selector': [
'title',
'fontSize',
'color',
'hPosition',
'isItalic',
'isBolder',
'remarkShow',
'fontFamily',
'letterSpace',
'fontShadow'
],
'legend-selector': ['orient', 'color', 'fontSize', 'hPosition', 'vPosition'],
'tooltip-selector': ['show', 'color', 'fontSize', 'backgroundColor']
}
axis: AxisType[] = ['xAxis', 'xAxisExt', 'extColor', 'filter']
axisConfig: AxisConfig = {
xAxis: {
name: `横轴 / ${t('chart.dimension')}`,
type: 'd',
limit: 1
},
xAxisExt: {
name: `纵轴 / ${t('chart.dimension')}`,
type: 'd',
limit: 1
},
extColor: {
name: `${t('chart.color')} / ${t('chart.dimension_or_quota')}`,
limit: 1
}
}
protected getDefaultLength = (chart, l) => {
const containerDom = document.getElementById(chart.container)
const containerHeight = containerDom?.clientHeight || 100
const containerWidth = containerDom?.clientWidth || 100
let defaultLength = containerHeight - containerHeight * 0.5
if (l.orient !== 'vertical') {
defaultLength = containerWidth - containerWidth * 0.5
}
return defaultLength
}
async drawChart(drawOptions: G2PlotDrawOptions<Heatmap>): Promise<Heatmap> {
const { chart, container, action } = drawOptions
const xAxis = deepCopy(chart.xAxis)
const xAxisExt = deepCopy(chart.xAxisExt)
const extColor = deepCopy(chart.extColor)
if (!xAxis?.length || !xAxisExt?.length || !extColor?.length) {
return
}
const xField = xAxis[0].dataeaseName
const xFieldExt = xAxisExt[0].dataeaseName
const extColorField = extColor[0].dataeaseName
// data
const data = cloneDeep(chart.data.tableRow)
data.forEach(i => {
Object.keys(i).forEach(key => {
if (key === '*') {
i['@'] = i[key]
}
})
})
// options
const initOptions: HeatmapOptions = {
data: data,
xField: xField,
yField: xFieldExt,
colorField: extColorField === '*' ? '@' : extColorField,
appendPadding: getPadding(chart),
meta: {
[xField]: {
type: 'cat'
},
[xFieldExt]: {
type: 'cat',
values: [...new Set(data.map(i => i[[xFieldExt]]))].reverse()
}
},
legend: {
layout: 'vertical',
position: 'right',
slidable: true,
label: {
align: 'left',
spacing: 10
}
}
}
chart.container = container
const options = this.setupOptions(chart, initOptions)
const { Heatmap } = await import('@antv/g2plot/esm/plots/heatmap')
const newChart = new Heatmap(container, options)
newChart.on('plot:click', param => {
if (!param.data?.data) {
return
}
const pointData = param.data.data
const dimensionList = []
const quotaList = []
chart.data.fields.forEach((item, index) => {
Object.keys(pointData).forEach(key => {
if (key.startsWith('f_') && item.dataeaseName === key) {
dimensionList.push({
id: item.id,
dataeaseName: item.dataeaseName,
value: pointData[key]
})
}
if (!key.startsWith('f_')) {
quotaList.push({
id: item.id,
dataeaseName: item.dataeaseName,
value: pointData[key]
})
}
})
})
action({
x: param.data.x,
y: param.data.y,
data: {
data: {
...param.data.data,
value: dimensionList[1].value,
name: dimensionList[1].id,
dimensionList: dimensionList,
quotaList: [dimensionList[1]]
}
}
})
})
newChart.on('afterrender', ev => {
const l = JSON.parse(JSON.stringify(parseJson(chart.customStyle).legend))
if (l.show) {
const rail = ev.view.getController('legend').option[extColor[0].dataeaseName]?.['rail']
if (rail) {
rail.defaultLength = this.getDefaultLength(chart, l)
}
}
})
return newChart
}
protected configBasicStyle(chart: Chart, options: HeatmapOptions): HeatmapOptions {
const basicStyle = parseJson(chart.customAttr).basicStyle
const color = basicStyle.colors?.map((ele, index) => {
return hexColorToRGBA(ele, basicStyle.alpha)
})
return {
...options,
color
}
}
protected configTooltip(chart: Chart, options: HeatmapOptions): HeatmapOptions {
let tooltip
let customAttr: DeepPartial<ChartAttr>
if (chart.customAttr) {
customAttr = parseJson(chart.customAttr)
// tooltip
if (customAttr.tooltip) {
const extColor = deepCopy(chart.extColor)
const xAxisExt = deepCopy(chart.xAxisExt)
const tooltipFiledList = [xAxisExt, extColor]
const t = JSON.parse(JSON.stringify(customAttr.tooltip))
if (t.show) {
tooltip = {
showTitle: true,
customItems(originalItems) {
const items = []
const createItem = (fieldObj, items, originalItems) => {
const name = fieldObj?.chartShowName ? fieldObj?.chartShowName : fieldObj?.name
let value = originalItems[0].data[fieldObj.dataeaseName]
if (!isNaN(Number(value))) {
value = valueFormatter(value, fieldObj?.formatterCfg)
}
items.push({
...originalItems[0],
name: name,
value: value
})
}
tooltipFiledList.forEach(field => {
createItem(field[0], items, originalItems)
})
return items
}
}
} else {
tooltip = false
}
}
}
return {
...options,
tooltip
}
}
protected configXAxis(chart: Chart, options: HeatmapOptions): HeatmapOptions {
const xAxis = getXAxis(chart, options)
return {
...options,
xAxis: xAxis ? { ...xAxis, grid: null } : false
}
}
protected configYAxis(chart: Chart, options: HeatmapOptions): HeatmapOptions {
const yAxis = getYAxis(chart)
return {
...options,
yAxis: yAxis ? { ...yAxis, grid: null } : false
}
}
protected configLegend(chart: Chart, options: HeatmapOptions): HeatmapOptions {
const tmpOptions = super.configLegend(chart, options)
if (tmpOptions.legend) {
const l = JSON.parse(JSON.stringify(parseJson(chart.customStyle).legend))
tmpOptions.legend.slidable = true
tmpOptions.legend.minHeight = 10
tmpOptions.legend.minWidth = 10
tmpOptions.legend.maxHeight = 600
tmpOptions.legend.maxWidth = 600
const containerDom = document.getElementById(chart.container)
const containerHeight = containerDom?.clientHeight || 100
const containerWidth = containerDom?.clientWidth || 100
let defaultLength = containerHeight - containerHeight * 0.5
if (l.orient === 'vertical') {
tmpOptions.legend.offsetY = -5
} else {
defaultLength = containerWidth - containerWidth * 0.5
}
tmpOptions.legend.rail = { defaultLength: defaultLength }
tmpOptions.legend.label = {
spacing: 10,
style: {
fill: l.color,
fontSize: l.fontSize
}
}
}
return tmpOptions
}
setupDefaultOptions(chart: ChartObj): ChartObj {
chart.customStyle.legend.orient = 'vertical'
chart.customStyle.legend.vPosition = 'center'
chart.customStyle.legend.hPosition = 'right'
chart.customStyle.legend.rail = { defaultLength: 100 }
return chart
}
protected configLabel(chart: Chart, options: HeatmapOptions): HeatmapOptions {
const tmpOptions = super.configLabel(chart, options)
if (tmpOptions.label) {
const extColor = deepCopy(chart.extColor)
const label = {
...tmpOptions.label,
position: 'middle',
layout: [{ type: 'hide-overlap' }, { type: 'limit-in-canvas' }],
formatter: data => {
const value = data[extColor[0]?.dataeaseName]
if (!isNaN(Number(value))) {
return valueFormatter(value, extColor[0]?.formatterCfg)
}
return value
}
}
return {
...tmpOptions,
label
}
}
return tmpOptions
}
protected setupOptions(chart: Chart, options: HeatmapOptions): HeatmapOptions {
return flow(
this.configTheme,
this.configXAxis,
this.configYAxis,
this.configBasicStyle,
this.configLegend,
this.configTooltip,
this.configLabel
)(chart, options)
}
constructor() {
super('t-heatmap', DEFAULT_DATA)
}
}

View File

@ -542,7 +542,7 @@ onBeforeUnmount(() => {
myChart?.destroy()
resizeObserver?.disconnect()
} catch (e) {
console.log(e)
console.warn(e)
}
})
</script>

View File

@ -587,7 +587,7 @@ onBeforeUnmount(() => {
myChart = null
resizeObserver?.disconnect()
} catch (e) {
console.log(e)
console.warn(e)
}
})

View File

@ -526,6 +526,7 @@ eventBus.on('handleNew', handleNew)
@loaded="XpackLoaded"
@load-fail="XpackLoaded"
/>
<xpack-component jsname="L2NvbXBvbmVudC90aHJlc2hvbGQtd2FybmluZy9UaHJlc2hvbGREaWFsb2c=" />
<canvas-cache-dialog ref="canvasCacheOutRef" @doUseCache="doUseCache"></canvas-cache-dialog>
<dv-preview
v-if="fullscreenFlag"

View File

@ -1,7 +1,9 @@
<script lang="ts" setup>
import { ref } from 'vue'
import VanCellGroup from 'vant/es/cell-group'
import mobileWholeBg from '@/assets/img/bg-mobile.png'
import mobileDeTop from '@/assets/img/mobile-de-top.png'
import { useAppearanceStoreWithOut } from '@/store/modules/appearance'
import { showToast } from 'vant'
import { loginApi, queryDekey } from '@/api/login'
import { useAppStoreWithOut } from '@/store/modules/app'
@ -22,6 +24,7 @@ const { wsCache } = useCache()
const appStore = useAppStoreWithOut()
const userStore = useUserStoreWithOut()
const router = useRouter()
const appearanceStore = useAppearanceStoreWithOut()
const username = ref('')
const password = ref('')
@ -55,7 +58,18 @@ const inputFocus = ref('')
const handleFocus = val => {
inputFocus.value = val
}
const mobileLogin = ref('')
const mobileLoginBg = ref('')
const loadAppearance = () => {
if (appearanceStore.getMobileLogin) {
mobileLogin.value = appearanceStore.getMobileLogin
}
if (appearanceStore.getMobileLoginBg) {
mobileLoginBg.value = appearanceStore.getMobileLoginBg
}
}
loadAppearance()
const handleBlur = () => {
inputFocus.value = ''
}
@ -101,8 +115,9 @@ const usernameEndValidate = ({ status, message }) => {
<template>
<div class="de-mobile-login" v-loading="duringLogin">
<img class="mobile-login_bg" :src="mobileLoginBg ? mobileLoginBg : mobileWholeBg" alt="" />
<div class="mobile-login-content">
<img width="120" height="31" :src="mobileDeTop" alt="" />
<img width="120" height="31" :src="mobileLogin ? mobileLogin : mobileDeTop" alt="" />
<div class="mobile-login-welcome">用户登录</div>
<van-form @submit="onSubmit">
<van-cell-group inset>
@ -157,7 +172,13 @@ const usernameEndValidate = ({ status, message }) => {
position: relative;
background-size: contain;
background-repeat: no-repeat;
background-image: url(../../../assets/img/bg-mobile.png);
.mobile-login_bg {
width: 100%;
height: 100%;
position: relative;
z-index: 1;
}
.mobile-login-content {
background: linear-gradient(180deg, rgba(255, 255, 255, 0.94) 0%, #ffffff 58.86%);
@ -170,6 +191,7 @@ const usernameEndValidate = ({ status, message }) => {
width: 100%;
height: 70%;
padding: 24px 16px;
z-index: 10;
--van-cell-group-inset-padding: 0;
--van-cell-group-inset-radius: 0;
--van-cell-group-background: transparent;

View File

@ -205,7 +205,6 @@ const submitForm = async () => {
.post({ url: '/engine/save', data: data })
.then(res => {
if (res !== undefined) {
console.log(res)
ElMessage.success(t('common.save_success'))
emits('saved')
reset()

View File

@ -1057,6 +1057,7 @@ const getMenuList = (val: boolean) => {
<el-form
ref="exportFormRef"
class="de-form-item"
@submit.prevent
:model="exportForm"
:rules="exportFormRules"
:before-close="closeExport"

View File

@ -186,7 +186,7 @@ const showApiData = () => {
originFieldItem.jsonFields = response.data.jsonFields
})
.catch(error => {
console.log(error?.message)
console.warn(error?.message)
})
loading.value = false
} else {
@ -295,7 +295,7 @@ const next = () => {
.catch(error => {
disabledNext.value = false
formLoading.value = false
console.log(error?.message)
console.warn(error?.message)
})
}
})

View File

@ -533,7 +533,8 @@ const defaultForm = {
description: '',
type: 'API',
apiConfiguration: [],
paramsConfiguration: []
paramsConfiguration: [],
enableDataFill: false
}
const form = reactive<Form>(cloneDeep(defaultForm))
const defaultForm2 = {
@ -859,6 +860,8 @@ defineExpose({
<style lang="less">
.datasource-drawer-fullscreen {
z-index: 1000 !important;
.ed-drawer__body {
padding: 0;
}

View File

@ -57,7 +57,7 @@ export default {
})
},
error => {
console.log('连接失败: ' + error)
console.error('连接失败: ' + error)
}
)
}
@ -66,10 +66,10 @@ export default {
if (stompClient && stompClient.connected) {
stompClient.disconnect(
function () {
console.log('断开连接')
console.info('断开连接')
},
function (error) {
console.log('断开连接失败: ' + error)
console.info('断开连接失败: ' + error)
}
)
}

@ -1 +1 @@
Subproject commit 7ebfc0b55262ee4f3bbd04defdb4e11128dc51d8
Subproject commit d47c2a58d47a50924b38e6d68b382cd9692c389e

View File

@ -0,0 +1,94 @@
package io.dataease.api.dataset.vo;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.dataease.api.chart.vo.ChartBaseVO;
import lombok.Data;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
@Data
public class CoreDatasetGroupVO implements Serializable {
private static final long serialVersionUID = 1L;
/**
* ID
*/
@JsonSerialize(using = ToStringSerializer.class)
private Long id;
/**
* 名称
*/
private String name;
/**
* 父级ID
*/
@JsonSerialize(using = ToStringSerializer.class)
private Long pid;
/**
* 当前分组处于第几级
*/
private Integer level;
/**
* node类型folder or dataset
*/
private String nodeType;
/**
* sql,union
*/
private String type;
/**
* 连接模式0-直连1-同步(包括excelapi等数据存在de中的表)
*/
private Integer mode;
/**
* 关联关系树
*/
private String info;
/**
* 创建人ID
*/
private String createBy;
/**
* 创建时间
*/
private Long createTime;
private String qrtzInstance;
/**
* 同步状态
*/
private String syncStatus;
/**
* 更新人ID
*/
private String updateBy;
/**
* 最后同步时间
*/
private Long lastUpdateTime;
/**
* 关联sql
*/
private String unionSql;
private List<CoreDatasetTableFieldVO> datasetFields = new ArrayList<>();
private List<ChartBaseVO> datasetViews = new ArrayList<>();
}

View File

@ -0,0 +1,132 @@
package io.dataease.api.dataset.vo;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@NoArgsConstructor
public class CoreDatasetTableFieldVO implements Serializable {
private static final long serialVersionUID = 1L;
/**
* ID
*/
@JsonSerialize(using = ToStringSerializer.class)
private Long id;
/**
* 数据源ID
*/
@JsonSerialize(using = ToStringSerializer.class)
private Long datasourceId;
/**
* 数据表ID
*/
@JsonSerialize(using = ToStringSerializer.class)
private Long datasetTableId;
/**
* 数据集ID
*/
@JsonSerialize(using = ToStringSerializer.class)
private Long datasetGroupId;
/**
* 图表ID
*/
@JsonSerialize(using = ToStringSerializer.class)
private Long chartId;
/**
* 原始字段名
*/
private String originName;
/**
* 字段名用于展示
*/
private String name;
/**
* 描述
*/
private String description;
/**
* de字段名用作唯一标识
*/
private String dataeaseName;
/**
* de字段别名
*/
private String fieldShortName;
/**
* 维度/指标标识 d:维度q:指标
*/
private String groupType;
/**
* 原始字段类型
*/
private String type;
private Integer size;
/**
* dataease字段类型0-文本1-时间2-整型数值3-浮点数值4-布尔5-地理位置6-二进制
*/
private Integer deType;
/**
* de记录的原始类型
*/
private Integer deExtractType;
/**
* 是否扩展字段 0原始 1复制 2计算字段...
*/
private Integer extField;
/**
* 是否选中
*/
private Boolean checked;
/**
* 列位置
*/
private Integer columnIndex;
/**
* 同步时间
*/
private Long lastSyncTime;
/**
* 精度
*/
private Integer accuracy;
private String dateFormat;
/**
* 时间格式类型
*/
private String dateFormatType;
// 附加ID 兼容自定义参数ID
private String attachId;
public CoreDatasetTableFieldVO(String attachId, String name, Integer deType) {
this.attachId = attachId;
this.name = name;
this.deType = deType;
}
}

View File

@ -10,10 +10,7 @@ import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@ -66,4 +63,12 @@ public interface ThresholdApi {
@Operation(summary = "预览信息")
@PostMapping("/preview")
String preview(@RequestBody ThresholdPreviewRequest request);
@Operation(summary = "视图是否设置了阈值告警")
@GetMapping("/anyThreshold/{chartId}")
boolean anyThreshold(@PathVariable("chartId") Long chartId);
@Operation(summary = "根据视图ID删除")
@GetMapping("/deleteWithChart/{chartId}")
void deleteWithChart(@PathVariable("chartId") Long chartId);
}

View File

@ -1,18 +1,27 @@
package io.dataease.api.visualization;
import io.dataease.api.dataset.vo.CoreDatasetGroupVO;
import io.dataease.api.visualization.dto.VisualizationOuterParamsDTO;
import io.dataease.api.visualization.response.VisualizationOuterParamsBaseResponse;
import org.springframework.web.bind.annotation.*;
import java.util.List;
public interface VisualizationOuterParamsApi {
@GetMapping("/queryWithVisualizationId/{dvId}")
VisualizationOuterParamsDTO queryWithVisualizationId(@PathVariable("dvId") String dvId);
@GetMapping("/queryWithVisualizationIdDS/{dvId}")
VisualizationOuterParamsDTO queryWithVisualizationIdDS(@PathVariable("dvId") String dvId);
@PostMapping("/updateOuterParamsSet")
void updateOuterParamsSet(@RequestBody VisualizationOuterParamsDTO OuterParamsDTO);
@GetMapping("/getOuterParamsInfo/{dvId}")
VisualizationOuterParamsBaseResponse getOuterParamsInfo(@PathVariable("dvId") String dvId);
@GetMapping("/queryDsWithVisualizationId/{dvId}")
List<CoreDatasetGroupVO> queryDsWithVisualizationId(@PathVariable("dvId") String dvId);
}

View File

@ -1,5 +1,7 @@
package io.dataease.api.visualization.dto;
import io.dataease.api.visualization.vo.VisualizationOuterParamsDsInfoVO;
import io.dataease.api.visualization.vo.VisualizationOuterParamsFilterInfoVO;
import io.dataease.api.visualization.vo.VisualizationOuterParamsInfoVO;
import io.dataease.api.visualization.vo.VisualizationOuterParamsTargetViewInfoVO;
import lombok.Data;
@ -20,4 +22,8 @@ public class VisualizationOuterParamsInfoDTO extends VisualizationOuterParamsInf
//目标联动参数 targetViewId#targetFieldId
private List<String> targetInfoList;
private List<VisualizationOuterParamsDsInfoVO> dsInfoVOList = new ArrayList<>();
private List<VisualizationOuterParamsFilterInfoVO> filterInfoVOList = new ArrayList<>();
}

View File

@ -0,0 +1,19 @@
package io.dataease.api.visualization.vo;
import lombok.Data;
import java.util.List;
import java.util.Map;
@Data
public class VisualizationOuterParamsDsInfoVO {
private String dsName;
private String dsId;
private List targetFieldInfo;
private Map<String,Boolean> viewCheckedInfo;
}

View File

@ -0,0 +1,15 @@
package io.dataease.api.visualization.vo;
import lombok.Data;
import java.util.List;
import java.util.Map;
@Data
public class VisualizationOuterParamsFilterInfoVO {
private String filterComponentId;
private String filterId;
}

View File

@ -1,6 +1,6 @@
package io.dataease.api.visualization.vo;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
@ -12,6 +12,7 @@ import java.io.Serializable;
* @author fit2cloud
* @since 2024-03-08
*/
@Data
public class VisualizationOuterParamsTargetViewInfoVO implements Serializable {
private static final long serialVersionUID = 1L;
@ -31,6 +32,11 @@ public class VisualizationOuterParamsTargetViewInfoVO implements Serializable {
*/
private String targetViewId;
/**
* 联动数据集id/联动过滤组件id
*/
private String targetDsId;
/**
* 联动字段ID
*/
@ -45,64 +51,4 @@ public class VisualizationOuterParamsTargetViewInfoVO implements Serializable {
* 复制来源ID
*/
private String copyId;
public String getTargetId() {
return targetId;
}
public void setTargetId(String targetId) {
this.targetId = targetId;
}
public String getParamsInfoId() {
return paramsInfoId;
}
public void setParamsInfoId(String paramsInfoId) {
this.paramsInfoId = paramsInfoId;
}
public String getTargetViewId() {
return targetViewId;
}
public void setTargetViewId(String targetViewId) {
this.targetViewId = targetViewId;
}
public String getTargetFieldId() {
return targetFieldId;
}
public void setTargetFieldId(String targetFieldId) {
this.targetFieldId = targetFieldId;
}
public String getCopyFrom() {
return copyFrom;
}
public void setCopyFrom(String copyFrom) {
this.copyFrom = copyFrom;
}
public String getCopyId() {
return copyId;
}
public void setCopyId(String copyId) {
this.copyId = copyId;
}
@Override
public String toString() {
return "VisualizationOuterParamsTargetViewInfo{" +
"targetId = " + targetId +
", paramsInfoId = " + paramsInfoId +
", targetViewId = " + targetViewId +
", targetFieldId = " + targetFieldId +
", copyFrom = " + copyFrom +
", copyId = " + copyId +
"}";
}
}

View File

@ -80,8 +80,8 @@ public interface DataFillingApi {
@PostMapping("/task/logMsg")
String logMsg(@RequestBody ReportInstanceMsgRequest request);
@PostMapping("/task/page/{goPage}/{pageSize}")
IPage<ReportGridVO> taskPager(@PathVariable("goPage") int goPage, @PathVariable("pageSize") int pageSize, @RequestBody DfTaskInfoRequest request);
@PostMapping("/form/{formId}/task/page/{goPage}/{pageSize}")
IPage<ReportGridVO> taskPager(@PathVariable("formId") Long formId, @PathVariable("goPage") int goPage, @PathVariable("pageSize") int pageSize, @RequestBody DfTaskInfoRequest request);
@PostMapping("/sub-task/page/{goPage}/{pageSize}")
IPage<DfSubTaskVo> subTaskPager(@PathVariable("goPage") int goPage, @PathVariable("pageSize") int pageSize, @RequestBody DfSubTaskInfoRequest request);

View File

@ -180,6 +180,11 @@ public abstract class Provider {
return s;
}
public String replaceComment(String s) {
String regex = "/\\*[\\s\\S]*?\\*/|-- .*";
return s.replaceAll(regex, " ");
}
public SqlDialect getDialect(DatasourceSchemaDTO coreDatasource) {
SqlDialect sqlDialect = null;
DatasourceConfiguration.DatasourceType datasourceType = DatasourceConfiguration.DatasourceType.valueOf(coreDatasource.getType());

View File

@ -9,5 +9,6 @@ public enum ChartAxis {
yAxis,
yAxisExt,
drill,
extColor,
extBubble;
}

View File

@ -224,4 +224,6 @@ public class ChartViewBaseDTO implements Serializable {
*/
private List<CalParam> calParams;
private List<ChartViewFieldDTO> extColor;
}