diff --git a/backend/src/main/java/io/dataease/commons/utils/ExcelXlsxReader.java b/backend/src/main/java/io/dataease/commons/utils/ExcelXlsxReader.java index dda075e2c7..9ee28d1ad1 100644 --- a/backend/src/main/java/io/dataease/commons/utils/ExcelXlsxReader.java +++ b/backend/src/main/java/io/dataease/commons/utils/ExcelXlsxReader.java @@ -33,7 +33,7 @@ import java.util.*; public class ExcelXlsxReader extends DefaultHandler { /** - * 自定义获取表格某些信息 + * 自定义获取表格某些信 */ public Map map = new TreeMap(); /** diff --git a/backend/src/main/java/io/dataease/controller/dataset/DataSetGroupController.java b/backend/src/main/java/io/dataease/controller/dataset/DataSetGroupController.java index 38f63df659..876c7ab312 100644 --- a/backend/src/main/java/io/dataease/controller/dataset/DataSetGroupController.java +++ b/backend/src/main/java/io/dataease/controller/dataset/DataSetGroupController.java @@ -10,6 +10,7 @@ import io.dataease.controller.request.dataset.DataSetGroupRequest; import io.dataease.dto.dataset.DataSetGroupDTO; import io.dataease.service.dataset.DataSetGroupService; import io.dataease.service.dataset.ExtractDataService; +import io.dataease.service.kettle.KettleService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.apache.shiro.authz.annotation.Logical; @@ -32,6 +33,8 @@ public class DataSetGroupController { private DataSetGroupService dataSetGroupService; @Resource private ExtractDataService extractDataService; + @Resource + private KettleService kettleService; @DePermissions(value = { @DePermission(type = DePermissionType.DATASET, value = "id"), @@ -71,6 +74,6 @@ public class DataSetGroupController { @ApiIgnore @PostMapping("/isKettleRunning") public boolean isKettleRunning() { - return extractDataService.isKettleRunning(); + return kettleService.isKettleRunning(); } } diff --git a/backend/src/main/java/io/dataease/controller/engine/EngineController.java b/backend/src/main/java/io/dataease/controller/engine/EngineController.java index c032534158..85572b13ec 100644 --- a/backend/src/main/java/io/dataease/controller/engine/EngineController.java +++ b/backend/src/main/java/io/dataease/controller/engine/EngineController.java @@ -42,4 +42,6 @@ public class EngineController { return engineService.save(engine); } + + } diff --git a/backend/src/main/java/io/dataease/controller/engine/KettleController.java b/backend/src/main/java/io/dataease/controller/engine/KettleController.java new file mode 100644 index 0000000000..11756093cd --- /dev/null +++ b/backend/src/main/java/io/dataease/controller/engine/KettleController.java @@ -0,0 +1,66 @@ +package io.dataease.controller.engine; + + +import com.github.pagehelper.Page; +import com.github.pagehelper.PageHelper; +import io.dataease.auth.annotation.DePermission; +import io.dataease.base.domain.DeEngine; +import io.dataease.commons.constants.DePermissionType; +import io.dataease.commons.constants.ResourceAuthLevel; +import io.dataease.commons.utils.PageUtils; +import io.dataease.commons.utils.Pager; +import io.dataease.controller.ResultHolder; +import io.dataease.dto.KettleDTO; +import io.dataease.plugins.common.entity.XpackConditionEntity; +import io.dataease.plugins.common.entity.XpackGridRequest; +import io.dataease.plugins.config.SpringContextUtil; +import io.dataease.plugins.xpack.auth.dto.request.DataSetColumnPermissionsDTO; +import io.dataease.plugins.xpack.auth.service.ColumnPermissionService; +import io.dataease.service.kettle.KettleService; +import io.swagger.annotations.ApiOperation; +import org.springframework.web.bind.annotation.*; +import springfox.documentation.annotations.ApiIgnore; + +import javax.annotation.Resource; +import java.util.ArrayList; +import java.util.List; + +@ApiIgnore +@RequestMapping("kettle") +@RestController +public class KettleController { + + @Resource + private KettleService kettleService; + + @ApiIgnore + @PostMapping("save") + public ResultHolder save(@RequestBody DeEngine engine) throws Exception{ + return kettleService.save(engine); + } + + + @ApiIgnore + @PostMapping("validate") + public void validate(@RequestBody KettleDTO kettleDTO) throws Exception{ + kettleService.validate(kettleDTO); + } + + @ApiIgnore + @PostMapping("validate/{id}") + public ResultHolder validate(@PathVariable String id) throws Exception{ + return kettleService.validate(id); + } + + @PostMapping("/pageList/{goPage}/{pageSize}") + public Pager> pageList( @PathVariable int goPage, @PathVariable int pageSize) { + Page page = PageHelper.startPage(goPage, pageSize, true); + return PageUtils.setPageInfo(page, kettleService.pageList()); + } + + @ApiIgnore + @DeleteMapping("delete/{id}") + public void delete(@PathVariable String id) throws Exception{ + kettleService.delete(id); + } +} diff --git a/backend/src/main/java/io/dataease/dto/KettleDTO.java b/backend/src/main/java/io/dataease/dto/KettleDTO.java new file mode 100644 index 0000000000..23e7fb2327 --- /dev/null +++ b/backend/src/main/java/io/dataease/dto/KettleDTO.java @@ -0,0 +1,11 @@ +package io.dataease.dto; + +import lombok.Data; + +@Data +public class KettleDTO { + private String carte; + private String port; + private String user; + private String passwd; +} diff --git a/backend/src/main/java/io/dataease/dto/datasource/DorisConfiguration.java b/backend/src/main/java/io/dataease/dto/datasource/DorisConfiguration.java index 18f3f41806..757c58b41a 100644 --- a/backend/src/main/java/io/dataease/dto/datasource/DorisConfiguration.java +++ b/backend/src/main/java/io/dataease/dto/datasource/DorisConfiguration.java @@ -7,5 +7,8 @@ import lombok.Setter; @Setter public class DorisConfiguration extends MysqlConfiguration { - private Integer httpPort; + private Integer httpPort = 8030; + + private Integer replicationNum = 1; + private Integer bucketNum = 10; } diff --git a/backend/src/main/java/io/dataease/job/sechedule/Schedular.java b/backend/src/main/java/io/dataease/job/sechedule/Schedular.java index 87c0d4c3b6..6a1693e6ff 100644 --- a/backend/src/main/java/io/dataease/job/sechedule/Schedular.java +++ b/backend/src/main/java/io/dataease/job/sechedule/Schedular.java @@ -3,6 +3,7 @@ package io.dataease.job.sechedule; import com.fit2cloud.quartz.anno.QuartzScheduled; import io.dataease.service.datasource.DatasourceService; import io.dataease.service.dataset.DataSetTableService; +import io.dataease.service.kettle.KettleService; import org.springframework.stereotype.Component; import javax.annotation.Resource; @@ -13,6 +14,8 @@ public class Schedular { private DataSetTableService dataSetTableService; @Resource private DatasourceService datasourceService; + @Resource + private KettleService kettleService; @QuartzScheduled(cron = "0 0/3 * * * ?") public void updateDatasetTableStatus() { @@ -24,4 +27,9 @@ public class Schedular { datasourceService.updateDatasourceStatus(); } + @QuartzScheduled(cron = "0 0/30 * * * ?") + public void updateKettleStatus() { + kettleService.updateKettleStatus(); + } + } diff --git a/backend/src/main/java/io/dataease/provider/DDLProvider.java b/backend/src/main/java/io/dataease/provider/DDLProvider.java index 758e9fc925..ea238d8957 100644 --- a/backend/src/main/java/io/dataease/provider/DDLProvider.java +++ b/backend/src/main/java/io/dataease/provider/DDLProvider.java @@ -1,6 +1,7 @@ package io.dataease.provider; import io.dataease.base.domain.DatasetTableField; +import io.dataease.base.domain.Datasource; import java.util.List; @@ -17,7 +18,7 @@ public abstract class DDLProvider { public abstract String replaceTable(String name); - public abstract String createTableSql(String name, List datasetTableFields); + public abstract String createTableSql(String name, List datasetTableFields, Datasource engine); public abstract String insertSql(String name, List dataList, int page, int pageNumber); } diff --git a/backend/src/main/java/io/dataease/provider/DDLProviderImpl.java b/backend/src/main/java/io/dataease/provider/DDLProviderImpl.java index f90781fcb3..0e53560056 100644 --- a/backend/src/main/java/io/dataease/provider/DDLProviderImpl.java +++ b/backend/src/main/java/io/dataease/provider/DDLProviderImpl.java @@ -1,6 +1,7 @@ package io.dataease.provider; import io.dataease.base.domain.DatasetTableField; +import io.dataease.base.domain.Datasource; import io.dataease.commons.utils.Md5Utils; import java.util.Arrays; @@ -28,7 +29,7 @@ public class DDLProviderImpl extends DDLProvider { } @Override - public String createTableSql(String name, List datasetTableFields) { + public String createTableSql(String name, List datasetTableFields, Datasource engine) { return null; } diff --git a/backend/src/main/java/io/dataease/provider/datasource/JdbcProvider.java b/backend/src/main/java/io/dataease/provider/datasource/JdbcProvider.java index af64cfca60..4786df662f 100644 --- a/backend/src/main/java/io/dataease/provider/datasource/JdbcProvider.java +++ b/backend/src/main/java/io/dataease/provider/datasource/JdbcProvider.java @@ -487,7 +487,6 @@ public class JdbcProvider extends DatasourceProvider { break; case impala: ImpalaConfiguration impalaConfiguration = new Gson().fromJson(datasourceRequest.getDatasource().getConfiguration(), ImpalaConfiguration.class); - System.out.println(new Gson().toJson(impalaConfiguration)); username = impalaConfiguration.getUsername(); password = impalaConfiguration.getPassword(); driver = impalaConfiguration.getDriver(); diff --git a/backend/src/main/java/io/dataease/provider/engine/doris/DorisDDLProvider.java b/backend/src/main/java/io/dataease/provider/engine/doris/DorisDDLProvider.java index 1d9965e2ca..950e146898 100644 --- a/backend/src/main/java/io/dataease/provider/engine/doris/DorisDDLProvider.java +++ b/backend/src/main/java/io/dataease/provider/engine/doris/DorisDDLProvider.java @@ -1,7 +1,12 @@ package io.dataease.provider.engine.doris; +import com.google.gson.Gson; import io.dataease.base.domain.DatasetTableField; +import io.dataease.base.domain.Datasource; import io.dataease.commons.utils.TableUtils; +import io.dataease.dto.datasource.DorisConfiguration; +import io.dataease.dto.datasource.JdbcConfiguration; +import io.dataease.dto.datasource.MysqlConfiguration; import io.dataease.provider.DDLProviderImpl; import org.springframework.stereotype.Service; @@ -16,8 +21,8 @@ public class DorisDDLProvider extends DDLProviderImpl { private static final String creatTableSql = "CREATE TABLE IF NOT EXISTS `TABLE_NAME`" + "Column_Fields" + "UNIQUE KEY(dataease_uuid)\n" + - "DISTRIBUTED BY HASH(dataease_uuid) BUCKETS 10\n" + - "PROPERTIES(\"replication_num\" = \"1\");"; + "DISTRIBUTED BY HASH(dataease_uuid) BUCKETS BUCKETS_NUM\n" + + "PROPERTIES(\"replication_num\" = \"ReplicationNum\");"; @Override public String createView(String name, String viewSQL) { @@ -41,9 +46,12 @@ public class DorisDDLProvider extends DDLProviderImpl { } @Override - public String createTableSql(String tableName, List datasetTableFields) { + public String createTableSql(String tableName, List datasetTableFields, Datasource engine) { + DorisConfiguration dorisConfiguration = new Gson().fromJson(engine.getConfiguration(), DorisConfiguration.class); String dorisTableColumnSql = createDorisTableColumnSql(datasetTableFields); - return creatTableSql.replace("TABLE_NAME", tableName).replace("Column_Fields", dorisTableColumnSql); + return creatTableSql.replace("TABLE_NAME", tableName).replace("Column_Fields", dorisTableColumnSql) + .replace("BUCKETS_NUM", dorisConfiguration.getBucketNum().toString()) + .replace("ReplicationNum", dorisConfiguration.getReplicationNum().toString()); } private String createDorisTableColumnSql(final List datasetTableFields) { diff --git a/backend/src/main/java/io/dataease/provider/engine/mysql/MysqlDDLProvider.java b/backend/src/main/java/io/dataease/provider/engine/mysql/MysqlDDLProvider.java index 91ba3ccf97..a920e7d01f 100644 --- a/backend/src/main/java/io/dataease/provider/engine/mysql/MysqlDDLProvider.java +++ b/backend/src/main/java/io/dataease/provider/engine/mysql/MysqlDDLProvider.java @@ -1,6 +1,7 @@ package io.dataease.provider.engine.mysql; import io.dataease.base.domain.DatasetTableField; +import io.dataease.base.domain.Datasource; import io.dataease.commons.utils.TableUtils; import io.dataease.provider.DDLProviderImpl; import org.springframework.stereotype.Service; @@ -43,7 +44,7 @@ public class MysqlDDLProvider extends DDLProviderImpl { } @Override - public String createTableSql(String tableName, List datasetTableFields) { + public String createTableSql(String tableName, List datasetTableFields, Datasource engine) { String dorisTableColumnSql = createDorisTableColumnSql(datasetTableFields); return creatTableSql.replace("TABLE_NAME", tableName).replace("Column_Fields", dorisTableColumnSql); } diff --git a/backend/src/main/java/io/dataease/provider/engine/mysql/MysqlQueryProvider.java b/backend/src/main/java/io/dataease/provider/engine/mysql/MysqlQueryProvider.java index eeeef6fac3..03e8cb85f1 100644 --- a/backend/src/main/java/io/dataease/provider/engine/mysql/MysqlQueryProvider.java +++ b/backend/src/main/java/io/dataease/provider/engine/mysql/MysqlQueryProvider.java @@ -778,8 +778,8 @@ public class MysqlQueryProvider extends QueryProvider { if (field.getDeExtractType() == 2 || field.getDeExtractType() == 3 || field.getDeExtractType() == 4) { whereName = originName; } - } else if (field.getDeType() == 0) { - whereName = String.format(MysqlConstants.CAST, originName, MysqlConstants.VARCHAR); + } else if (field.getDeType() == 0 && field.getDeExtractType() == 0) { + whereName = String.format(MysqlConstants.CAST, originName, MysqlConstants.CHAR); } else { whereName = originName; } @@ -865,8 +865,8 @@ public class MysqlQueryProvider extends QueryProvider { String cast = String.format(MysqlConstants.CAST, originName, MysqlConstants.DEFAULT_INT_FORMAT) + "/1000"; whereName = String.format(MysqlConstants.FROM_UNIXTIME, cast, MysqlConstants.DEFAULT_DATE_FORMAT); } - } else if (field.getDeType() == 0) { - whereName = String.format(MysqlConstants.CAST, originName, MysqlConstants.VARCHAR); + } else if (field.getDeType() == 0 && field.getDeExtractType() == 0) { + whereName = String.format(MysqlConstants.CAST, originName, MysqlConstants.CHAR); } else if (field.getDeType() == 2 || field.getDeType() == 3) { if (field.getDeExtractType() == 0 || field.getDeExtractType() == 5) { whereName = String.format(MysqlConstants.CAST, originName, MysqlConstants.DEFAULT_FLOAT_FORMAT); @@ -967,8 +967,8 @@ public class MysqlQueryProvider extends QueryProvider { String from_unixtime = String.format(MysqlConstants.FROM_UNIXTIME, cast, MysqlConstants.DEFAULT_DATE_FORMAT); fieldName = String.format(MysqlConstants.DATE_FORMAT, from_unixtime, format); } - } else if (x.getDeType() == 0) { - fieldName = String.format(MysqlConstants.CAST, originField, MysqlConstants.VARCHAR); + } else if (x.getDeType() == 0 && x.getDeExtractType() == 0) { + fieldName = String.format(MysqlConstants.CAST, originField, MysqlConstants.CHAR); } else { fieldName = originField; } diff --git a/backend/src/main/java/io/dataease/provider/query/impala/ImpalaQueryProvider.java b/backend/src/main/java/io/dataease/provider/query/impala/ImpalaQueryProvider.java index 1cf0c5a7e6..2a432454f4 100644 --- a/backend/src/main/java/io/dataease/provider/query/impala/ImpalaQueryProvider.java +++ b/backend/src/main/java/io/dataease/provider/query/impala/ImpalaQueryProvider.java @@ -92,24 +92,24 @@ public class ImpalaQueryProvider extends QueryProvider { String fieldAlias = String.format(SQLConstants.FIELD_ALIAS_X_PREFIX, i); String fieldName = ""; // 处理横轴字段 - if (f.getDeExtractType() == DeTypeConstants.DE_TIME) { + if (f.getDeExtractType() == DeTypeConstants.DE_TIME) { //时间转数值 if (f.getDeType() == 2 || f.getDeType() == 3) { fieldName = String.format(ImpalaConstants.UNIX_TIMESTAMP, originField) + "*1000"; } else { fieldName = originField; } - } else if (f.getDeExtractType() == DeTypeConstants.DE_STRING) { + } else if (f.getDeExtractType() == DeTypeConstants.DE_STRING) { //字符串转时间 if (f.getDeType() == DeTypeConstants.DE_INT) { fieldName = String.format(ImpalaConstants.CAST, originField, ImpalaConstants.DEFAULT_INT_FORMAT); } else if (f.getDeType() == DeTypeConstants.DE_FLOAT) { fieldName = String.format(ImpalaConstants.CAST, originField, ImpalaConstants.DEFAULT_FLOAT_FORMAT); } else if (f.getDeType() == DeTypeConstants.DE_TIME) { - fieldName = String.format(ImpalaConstants.STR_TO_DATE, originField, ImpalaConstants.DEFAULT_DATE_FORMAT); + fieldName = String.format(ImpalaConstants.DATE_FORMAT, originField, ImpalaConstants.DEFAULT_DATE_FORMAT); } else { fieldName = originField; } } else { - if (f.getDeType() == DeTypeConstants.DE_TIME) { + if (f.getDeType() == DeTypeConstants.DE_TIME) {//数值转时间 String cast = String.format(ImpalaConstants.CAST, originField, ImpalaConstants.DEFAULT_INT_FORMAT) + "/1000"; fieldName = String.format(ImpalaConstants.FROM_UNIXTIME, cast, ImpalaConstants.DEFAULT_DATE_FORMAT); } else if (f.getDeType() == 2) { @@ -745,7 +745,7 @@ public class ImpalaQueryProvider extends QueryProvider { } if (field.getDeType() == DeTypeConstants.DE_TIME) { if (field.getDeExtractType() == DeTypeConstants.DE_STRING || field.getDeExtractType() == 5) { - whereName = String.format(ImpalaConstants.STR_TO_DATE, originName, ImpalaConstants.DEFAULT_DATE_FORMAT); + whereName = String.format(ImpalaConstants.DATE_FORMAT, originName, ImpalaConstants.DEFAULT_DATE_FORMAT); } if (field.getDeExtractType() == DeTypeConstants.DE_INT || field.getDeExtractType() == 3 || field.getDeExtractType() == 4) { String cast = String.format(ImpalaConstants.CAST, originName, ImpalaConstants.DEFAULT_INT_FORMAT) + "/1000"; @@ -792,7 +792,11 @@ public class ImpalaQueryProvider extends QueryProvider { } else if (StringUtils.containsIgnoreCase(filterItemDTO.getTerm(), "like")) { whereValue = "'%" + value + "%'"; } else { - whereValue = String.format(ImpalaConstants.WHERE_VALUE_VALUE, value); + if(field.getDeExtractType() == DeTypeConstants.DE_INT || field.getDeExtractType() == DeTypeConstants.DE_FLOAT|| field.getDeExtractType() == DeTypeConstants.DE_BOOL){ + whereValue = String.format(ImpalaConstants.WHERE_NUMBER_VALUE_VALUE, value); + }else { + whereValue = String.format(ImpalaConstants.WHERE_VALUE_VALUE, value); + } } list.add(SQLObj.builder() .whereField(whereName) @@ -837,7 +841,7 @@ public class ImpalaQueryProvider extends QueryProvider { if (field.getDeType() == DeTypeConstants.DE_TIME) { if (field.getDeExtractType() == DeTypeConstants.DE_STRING || field.getDeExtractType() == 5) { - whereName = String.format(ImpalaConstants.STR_TO_DATE, originName, ImpalaConstants.DEFAULT_DATE_FORMAT); + whereName = String.format(ImpalaConstants.DATE_FORMAT, originName, ImpalaConstants.DEFAULT_DATE_FORMAT); } if (field.getDeExtractType() == DeTypeConstants.DE_INT || field.getDeExtractType() == 3 || field.getDeExtractType() == 4) { String cast = String.format(ImpalaConstants.CAST, originName, ImpalaConstants.DEFAULT_INT_FORMAT) + "/1000"; @@ -875,7 +879,11 @@ public class ImpalaQueryProvider extends QueryProvider { whereValue = String.format(ImpalaConstants.WHERE_BETWEEN, value.get(0), value.get(1)); } } else { - whereValue = String.format(ImpalaConstants.WHERE_VALUE_VALUE, value.get(0)); + if(field.getDeExtractType() == DeTypeConstants.DE_INT || field.getDeExtractType() == DeTypeConstants.DE_FLOAT|| field.getDeExtractType() == DeTypeConstants.DE_BOOL){ + whereValue = String.format(ImpalaConstants.WHERE_NUMBER_VALUE_VALUE, value.get(0)); + }else { + whereValue = String.format(ImpalaConstants.WHERE_VALUE_VALUE, value.get(0)); + } } list.add(SQLObj.builder() .whereField(whereName) @@ -957,44 +965,6 @@ public class ImpalaQueryProvider extends QueryProvider { .build(); } - private List getXWheres(ChartViewFieldDTO x, String originField, String fieldAlias) { - List list = new ArrayList<>(); - if (CollectionUtils.isNotEmpty(x.getFilter()) && x.getFilter().size() > 0) { - x.getFilter().forEach(f -> { - String whereName = ""; - String whereTerm = transMysqlFilterTerm(f.getTerm()); - String whereValue = ""; - if (x.getDeType() == DeTypeConstants.DE_TIME && x.getDeExtractType() != 1) { - String cast = String.format(ImpalaConstants.CAST, originField, ImpalaConstants.DEFAULT_INT_FORMAT) + "/1000"; - whereName = String.format(ImpalaConstants.FROM_UNIXTIME, cast, ImpalaConstants.DEFAULT_DATE_FORMAT); - } else { - whereName = originField; - } - if (StringUtils.equalsIgnoreCase(f.getTerm(), "null")) { - whereValue = ""; - } else if (StringUtils.equalsIgnoreCase(f.getTerm(), "not_null")) { - whereValue = ""; - } else if (StringUtils.equalsIgnoreCase(f.getTerm(), "empty")) { - whereValue = "''"; - } else if (StringUtils.equalsIgnoreCase(f.getTerm(), "not_empty")) { - whereValue = "''"; - } else if (StringUtils.containsIgnoreCase(f.getTerm(), "in")) { - whereValue = "('" + StringUtils.join(f.getValue(), "','") + "')"; - } else if (StringUtils.containsIgnoreCase(f.getTerm(), "like")) { - whereValue = "'%" + f.getValue() + "%'"; - } else { - whereValue = String.format(ImpalaConstants.WHERE_VALUE_VALUE, f.getValue()); - } - list.add(SQLObj.builder() - .whereField(whereName) - .whereAlias(fieldAlias) - .whereTermAndValue(whereTerm + whereValue) - .build()); - }); - } - return list; - } - private SQLObj getYFields(ChartViewFieldDTO y, String originField, String fieldAlias) { String fieldName = ""; if (StringUtils.equalsIgnoreCase(y.getOriginName(), "*")) { @@ -1037,7 +1007,11 @@ public class ImpalaQueryProvider extends QueryProvider { } else if (StringUtils.containsIgnoreCase(f.getTerm(), "like")) { whereValue = "'%" + f.getValue() + "%'"; } else { - whereValue = String.format(ImpalaConstants.WHERE_VALUE_VALUE, f.getValue()); + if(y.getDeExtractType() == DeTypeConstants.DE_INT || y.getDeExtractType() == DeTypeConstants.DE_FLOAT|| y.getDeExtractType() == DeTypeConstants.DE_BOOL){ + whereValue = String.format(ImpalaConstants.WHERE_NUMBER_VALUE_VALUE, f.getValue()); + }else { + whereValue = String.format(ImpalaConstants.WHERE_VALUE_VALUE, f.getValue()); + } } list.add(SQLObj.builder() .whereField(fieldAlias) diff --git a/backend/src/main/java/io/dataease/provider/query/mongodb/MongoQueryProvider.java b/backend/src/main/java/io/dataease/provider/query/mongodb/MongoQueryProvider.java index eec743a7eb..d7569fc37d 100644 --- a/backend/src/main/java/io/dataease/provider/query/mongodb/MongoQueryProvider.java +++ b/backend/src/main/java/io/dataease/provider/query/mongodb/MongoQueryProvider.java @@ -43,7 +43,6 @@ public class MongoQueryProvider extends QueryProvider { @Override public Integer transFieldType(String field) { - System.out.println(field); field = field.toUpperCase(); switch (field) { case "CHAR": diff --git a/backend/src/main/java/io/dataease/service/chart/ChartViewService.java b/backend/src/main/java/io/dataease/service/chart/ChartViewService.java index d6193cf237..02c11d0164 100644 --- a/backend/src/main/java/io/dataease/service/chart/ChartViewService.java +++ b/backend/src/main/java/io/dataease/service/chart/ChartViewService.java @@ -614,7 +614,7 @@ public class ChartViewService { } else { datasourceRequest.setQuery(qp.getSQL(tableName, xAxis, yAxis, fieldCustomFilter, extFilterList, ds, view)); } - // 仪表板有参数不实用缓存 + // 仪表板有参数不使用缓存 if (!cache || CollectionUtils.isNotEmpty(requestList.getFilter()) || CollectionUtils.isNotEmpty(requestList.getLinkageFilters()) || CollectionUtils.isNotEmpty(requestList.getDrill()) || CollectionUtils.isNotEmpty(rowPermissionFields) || fields.size() != columnPermissionFields.size()) { diff --git a/backend/src/main/java/io/dataease/service/dataset/ExtractDataService.java b/backend/src/main/java/io/dataease/service/dataset/ExtractDataService.java index 03afdf3c7e..6d6f441a42 100644 --- a/backend/src/main/java/io/dataease/service/dataset/ExtractDataService.java +++ b/backend/src/main/java/io/dataease/service/dataset/ExtractDataService.java @@ -25,6 +25,7 @@ import io.dataease.exception.DataEaseException; import io.dataease.listener.util.CacheUtils; import io.dataease.provider.QueryProvider; import io.dataease.service.engine.EngineService; +import io.dataease.service.kettle.KettleService; import io.dataease.service.message.DeMsgutil; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.io.FileUtils; @@ -98,6 +99,8 @@ public class ExtractDataService { private ExtChartViewMapper extChartViewMapper; @Resource private EngineService engineService; + @Resource + private KettleService kettleService; private static final String lastUpdateTime = "${__last_update_time__}"; private static final String currentUpdateTime = "${__current_update_time__}"; @@ -107,14 +110,6 @@ public class ExtractDataService { @Value("${kettle.files.keep:false}") private boolean kettleFilesKeep; - @Value("${carte.host:127.0.0.1}") - private String carte; - @Value("${carte.port:8080}") - private String port; - @Value("${carte.user:cluster}") - private String user; - @Value("${carte.passwd:cluster}") - private String passwd; private static final String shellScript = "result=`curl --location-trusted -u %s:%s -H \"label:%s\" -H \"column_separator:%s\" -H \"columns:%s\" -H \"merge_type: %s\" -T %s -XPUT http://%s:%s/api/%s/%s/_stream_load`\n" + "if [ $? -eq 0 ] ; then\n" + @@ -605,7 +600,7 @@ public class ExtractDataService { DatasourceRequest datasourceRequest = new DatasourceRequest(); datasourceRequest.setDatasource(engine); DDLProvider ddlProvider = ProviderFactory.getDDLProvider(engine.getType()); - datasourceRequest.setQuery(ddlProvider.createTableSql(tableName, datasetTableFields)); + datasourceRequest.setQuery(ddlProvider.createTableSql(tableName, datasetTableFields, engine)); jdbcProvider.exec(datasourceRequest); } @@ -730,7 +725,7 @@ public class ExtractDataService { break; } - SlaveServer remoteSlaveServer = getSlaveServer(); + SlaveServer remoteSlaveServer = kettleService.getSlaveServer(); JobExecutionConfiguration jobExecutionConfiguration = new JobExecutionConfiguration(); jobExecutionConfiguration.setRemoteServer(remoteSlaveServer); jobExecutionConfiguration.setRepository(repository); @@ -738,7 +733,6 @@ public class ExtractDataService { TransExecutionConfiguration transExecutionConfiguration = new TransExecutionConfiguration(); transExecutionConfiguration.setRepository(repository); transExecutionConfiguration.setRemoteServer(remoteSlaveServer); - String lastTranceId = Trans.sendToSlaveServer(transMeta, transExecutionConfiguration, repository, null); SlaveServerTransStatus transStatus = null; boolean executing = true; @@ -772,15 +766,6 @@ public class ExtractDataService { } } - private SlaveServer getSlaveServer() { - SlaveServer remoteSlaveServer = new SlaveServer(); - remoteSlaveServer.setHostname(carte);// 设置远程IP - remoteSlaveServer.setPort(port);// 端口 - remoteSlaveServer.setUsername(user); - remoteSlaveServer.setPassword(passwd); - return remoteSlaveServer; - } - private void generateJobFile(String extractType, DatasetTable datasetTable, String columnFields) throws Exception { if (engineService.isSimpleMode()) { return; @@ -1251,33 +1236,6 @@ public class ExtractDataService { } } - public boolean isKettleRunning() { - try { - if (!InetAddress.getByName(carte).isReachable(1000)) { - return false; - } - } catch (Exception e) { - return false; - } - HttpGet getMethod = new HttpGet("http://" + carte + ":" + port); - HttpClientManager.HttpClientBuilderFacade clientBuilder = HttpClientManager.getInstance().createBuilder(); - clientBuilder.setConnectionTimeout(1); - clientBuilder.setCredentials(user, passwd); - try { - CloseableHttpClient httpClient = clientBuilder.build(); - HttpResponse httpResponse = httpClient.execute(getMethod); - int statusCode = httpResponse.getStatusLine().getStatusCode(); - if (statusCode != -1 && statusCode < 400) { - httpResponse.getEntity().getContent().close(); - return true; - } else { - return false; - } - } catch (Exception e) { - return false; - } - } - private final static String handleBinaryType = " \t\tif(\"FIELD\".equalsIgnoreCase(filed)){\n" + " get(Fields.Out, filed).setValue(r, \"\");\n" + " get(Fields.Out, filed).getValueMeta().setType(2);\n" + diff --git a/backend/src/main/java/io/dataease/service/datasource/DatasourceService.java b/backend/src/main/java/io/dataease/service/datasource/DatasourceService.java index fca4f1f6a1..05d54cc081 100644 --- a/backend/src/main/java/io/dataease/service/datasource/DatasourceService.java +++ b/backend/src/main/java/io/dataease/service/datasource/DatasourceService.java @@ -59,6 +59,11 @@ public class DatasourceService { @DeCleaner(DePermissionType.DATASOURCE) public Datasource addDatasource(Datasource datasource) throws Exception{ + try{ + DatasourceTypes datasourceType = DatasourceTypes.valueOf(datasource.getType()); + }catch (Exception e){ + throw e; + } checkName(datasource); long currentTimeMillis = System.currentTimeMillis(); datasource.setId(UUID.randomUUID().toString()); diff --git a/backend/src/main/java/io/dataease/service/engine/EngineService.java b/backend/src/main/java/io/dataease/service/engine/EngineService.java index 181d1acc6b..7a7c6a2b43 100644 --- a/backend/src/main/java/io/dataease/service/engine/EngineService.java +++ b/backend/src/main/java/io/dataease/service/engine/EngineService.java @@ -1,14 +1,21 @@ package io.dataease.service.engine; +import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; +import com.google.gson.Gson; +import com.google.gson.JsonArray; import io.dataease.base.domain.Datasource; import io.dataease.base.domain.DeEngine; import io.dataease.base.domain.DeEngineExample; import io.dataease.base.mapper.DeEngineMapper; import io.dataease.commons.utils.BeanUtils; +import io.dataease.commons.utils.HttpClientConfig; +import io.dataease.commons.utils.HttpClientUtil; import io.dataease.controller.ResultHolder; import io.dataease.controller.request.datasource.DatasourceRequest; import io.dataease.dto.DatasourceDTO; +import io.dataease.dto.datasource.DorisConfiguration; +import io.dataease.listener.util.CacheUtils; import io.dataease.provider.ProviderFactory; import io.dataease.provider.datasource.DatasourceProvider; import io.dataease.service.datasource.DatasourceService; @@ -19,7 +26,9 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; +import java.util.Base64; import java.util.List; +import java.util.Optional; import java.util.UUID; @Service @@ -31,35 +40,39 @@ public class EngineService { private DeEngineMapper deEngineMapper; @Resource private DatasourceService datasource; - static private Datasource ds = null; - - public Boolean isLocalMode(){ + public Boolean isLocalMode() { return env.getProperty("engine_mode", "local").equalsIgnoreCase("local"); } - public Boolean isSimpleMode(){ + public Boolean isSimpleMode() { return env.getProperty("engine_mode", "local").equalsIgnoreCase("simple"); } - public Boolean isClusterMode(){ + public Boolean isClusterMode() { return env.getProperty("engine_mode", "local").equalsIgnoreCase("cluster"); } - public String mode(){ + public String mode() { return env.getProperty("engine_mode", "local"); } - public DeEngine info(){ - List deEngines = deEngineMapper.selectByExampleWithBLOBs(new DeEngineExample()); - if(CollectionUtils.isEmpty(deEngines)){ + public DeEngine info() { + DeEngineExample deEngineExample = new DeEngineExample(); + if (isClusterMode()) { + deEngineExample.createCriteria().andTypeEqualTo("engine_doris"); + } else { + deEngineExample.createCriteria().andTypeEqualTo("engine_mysql"); + } + List deEngines = deEngineMapper.selectByExampleWithBLOBs(deEngineExample); + if (CollectionUtils.isEmpty(deEngines)) { return new DeEngine(); } return deEngines.get(0); } public ResultHolder validate(DatasourceDTO datasource) throws Exception { - if(StringUtils.isEmpty(datasource.getType()) || StringUtils.isEmpty(datasource.getConfiguration())){ + if (StringUtils.isEmpty(datasource.getType()) || StringUtils.isEmpty(datasource.getConfiguration())) { throw new Exception("未完整设置数据引擎"); } try { @@ -67,39 +80,70 @@ public class EngineService { DatasourceRequest datasourceRequest = new DatasourceRequest(); datasourceRequest.setDatasource(datasource); datasourceProvider.checkStatus(datasourceRequest); - return ResultHolder.success(datasource); - }catch (Exception e){ - return ResultHolder.error("Datasource is invalid: " + e.getMessage()); + } catch (Exception e) { + return ResultHolder.error("Engine is invalid: " + e.getMessage()); } + + if (datasource.getType().equalsIgnoreCase("engine_doris")) { + DorisConfiguration dorisConfiguration = new Gson().fromJson(datasource.getConfiguration(), DorisConfiguration.class); + HttpClientConfig httpClientConfig = new HttpClientConfig(); + String authValue = "Basic " + Base64.getUrlEncoder().encodeToString((dorisConfiguration.getUsername() + + ":" + dorisConfiguration.getPassword()).getBytes()); + httpClientConfig.addHeader("Authorization", authValue); + String response; + try { + response = HttpClientUtil.get("http://" + dorisConfiguration.getHost() + ":" + dorisConfiguration.getHttpPort() + "/api/backends", httpClientConfig); + }catch (Exception e){ + return ResultHolder.error("Engine is invalid: " + e.getMessage()); + } + + JSONArray backends = Optional.ofNullable(JSONObject.parseObject(response).getJSONObject("data")).orElse(new JSONObject()).getJSONArray("backends"); + if(CollectionUtils.isEmpty(backends)){ + return ResultHolder.error("Engine is invalid: no backends found."); + } + + Integer alives = 0; + for (int i = 0; i < backends.size(); i++) { + JSONObject kv = backends.getJSONObject(i); + if (kv.getBoolean("is_alive")) { + alives ++; + } + } + + if(alives < dorisConfiguration.getReplicationNum()){ + return ResultHolder.error("Engine params is invalid: 副本数量不能大于节点数量."); + } + } + + return ResultHolder.success(datasource); } public ResultHolder save(DeEngine engine) throws Exception { - if(StringUtils.isEmpty(engine.getId())){ + if (StringUtils.isEmpty(engine.getId())) { engine.setId(UUID.randomUUID().toString()); deEngineMapper.insert(engine); - }else { + } else { deEngineMapper.updateByPrimaryKeyWithBLOBs(engine); + datasource.handleConnectionPool(getDeEngine(), "delete"); } - datasource.handleConnectionPool(this.ds, "delete"); setDs(engine); - datasource.handleConnectionPool(this.ds, "add"); + datasource.handleConnectionPool(getDeEngine(), "add"); return ResultHolder.success(engine); } - private void setDs(DeEngine engine){ - if(this.ds == null){ - this.ds = new Datasource(); - BeanUtils.copyBean(this.ds, engine); - }else { - BeanUtils.copyBean(this.ds, engine); - } + private void setDs(DeEngine engine) { + Datasource datasource = new Datasource(); + BeanUtils.copyBean(datasource, engine); + CacheUtils.put("ENGINE", "engine", datasource, null, null); } - public Datasource getDeEngine() throws Exception{ - if (this.ds != null) { - return this.ds; + public Datasource getDeEngine() throws Exception { + Object catcheEngine = CacheUtils.get("ENGINE", "engine"); + if (catcheEngine != null) { + return (Datasource) catcheEngine; } - if(isLocalMode()){ + + if (isLocalMode()) { JSONObject jsonObject = new JSONObject(); jsonObject.put("dataSourceType", "jdbc"); jsonObject.put("dataBase", env.getProperty("doris.db", "doris")); @@ -116,19 +160,26 @@ public class EngineService { engine.setType("engine_doris"); engine.setConfiguration(jsonObject.toJSONString()); setDs(engine); - }else { - List deEngines = deEngineMapper.selectByExampleWithBLOBs(new DeEngineExample()); - if(CollectionUtils.isEmpty(deEngines)){ + } + if (isClusterMode()) { + DeEngineExample engineExample = new DeEngineExample(); + engineExample.createCriteria().andTypeEqualTo("engine_doris"); + List deEngines = deEngineMapper.selectByExampleWithBLOBs(engineExample); + if (CollectionUtils.isEmpty(deEngines)) { throw new Exception("未设置数据引擎"); } setDs(deEngines.get(0)); } -// if(isSimpleMode()){ -// -// } - - //TODO cluster mode - return this.ds; + if (isSimpleMode()) { + DeEngineExample engineExample = new DeEngineExample(); + engineExample.createCriteria().andTypeEqualTo("engine_mysql"); + List deEngines = deEngineMapper.selectByExampleWithBLOBs(engineExample); + if (CollectionUtils.isEmpty(deEngines)) { + throw new Exception("未设置数据引擎"); + } + setDs(deEngines.get(0)); + } + return getDeEngine(); } diff --git a/backend/src/main/java/io/dataease/service/kettle/KettleService.java b/backend/src/main/java/io/dataease/service/kettle/KettleService.java new file mode 100644 index 0000000000..aff3dc667f --- /dev/null +++ b/backend/src/main/java/io/dataease/service/kettle/KettleService.java @@ -0,0 +1,150 @@ +package io.dataease.service.kettle; + +import com.google.gson.Gson; +import io.dataease.base.domain.DeEngine; +import io.dataease.base.domain.DeEngineExample; +import io.dataease.base.mapper.DeEngineMapper; +import io.dataease.commons.utils.HttpClientConfig; +import io.dataease.commons.utils.HttpClientUtil; +import io.dataease.controller.ResultHolder; +import io.dataease.dto.KettleDTO; +import io.dataease.service.engine.EngineService; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.checkerframework.checker.units.qual.K; +import org.pentaho.di.cluster.SlaveServer; +import org.pentaho.di.core.util.HttpClientManager; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.net.InetAddress; +import java.util.Base64; +import java.util.List; +import java.util.Random; +import java.util.UUID; +import java.util.stream.Collectors; + +@Service +public class KettleService { + + @Resource + private Environment env; + @Resource + private DeEngineMapper deEngineMapper; + @Resource + private EngineService engineService; + + public ResultHolder save(DeEngine kettle) throws Exception { + try { + validate(new Gson().fromJson(kettle.getConfiguration(), KettleDTO.class)); + kettle.setStatus("Success"); + }catch (Exception e){ + kettle.setStatus("Error"); + } + + if (StringUtils.isEmpty(kettle.getId())) { + kettle.setId(UUID.randomUUID().toString()); + kettle.setType("kettle"); + deEngineMapper.insert(kettle); + } else { + deEngineMapper.updateByPrimaryKeyWithBLOBs(kettle); + } + return ResultHolder.success(kettle); + } + + public void delete(String id){ + deEngineMapper.deleteByPrimaryKey(id); + } + + public void validate(KettleDTO kettleDTO) throws Exception { + HttpClientConfig httpClientConfig = new HttpClientConfig(); + String authValue = "Basic " + Base64.getUrlEncoder().encodeToString((kettleDTO.getUser() + + ":" + kettleDTO.getPasswd()).getBytes()); + httpClientConfig.addHeader("Authorization", authValue); + String response = HttpClientUtil.get("http://" + kettleDTO.getCarte() + ":" + kettleDTO.getPort() + "/kettle/status/", httpClientConfig); + } + + public ResultHolder validate(String id) { + DeEngine kettle = deEngineMapper.selectByPrimaryKey(id); + try { + validate(new Gson().fromJson(kettle.getConfiguration(), KettleDTO.class)); + kettle.setStatus("Success"); + deEngineMapper.updateByPrimaryKeyWithBLOBs(kettle); + return ResultHolder.success(kettle); + }catch (Exception e){ + kettle.setStatus("Error"); + deEngineMapper.updateByPrimaryKeyWithBLOBs(kettle); + return ResultHolder.error(e.getMessage()); + } + } + + public List pageList(){ + DeEngineExample deEngineExample = new DeEngineExample(); + deEngineExample.createCriteria().andTypeEqualTo("kettle"); + return deEngineMapper.selectByExampleWithBLOBs(deEngineExample); + } + + public void updateKettleStatus(){ + if(!engineService.isClusterMode()){ + return; + } + Listkettles = pageList(); + kettles.forEach(kettle -> { + validate(kettle.getId()); + }); + } + + public SlaveServer getSlaveServer() throws Exception{ + SlaveServer remoteSlaveServer = new SlaveServer(); + if(engineService.isLocalMode()){ + remoteSlaveServer.setHostname(env.getProperty("carte.host", "127.0.0.1")); + remoteSlaveServer.setPort(env.getProperty("carte.port", "8080")); + remoteSlaveServer.setUsername(env.getProperty("carte.user", "cluster")); + remoteSlaveServer.setPassword(env.getProperty("carte.passwd", "cluster")); + }else { + List kettles = pageList().stream().filter(kettle -> kettle.getStatus() != null && kettle.getStatus().equalsIgnoreCase("Success")) + .collect(Collectors.toList()); + if(CollectionUtils.isEmpty(kettles)){ + throw new Exception("No valid kettle service."); + } + DeEngine kettle = kettles.get(new Random().nextInt(kettles.size())); + KettleDTO kettleDTO = new Gson().fromJson(kettle.getConfiguration(), KettleDTO.class); + remoteSlaveServer.setHostname(kettleDTO.getCarte()); + remoteSlaveServer.setPort(kettleDTO.getPort()); + remoteSlaveServer.setUsername(kettleDTO.getUser()); + remoteSlaveServer.setPort(kettleDTO.getPasswd()); + } + return remoteSlaveServer; + } + + public boolean isKettleRunning() { + if(engineService.isLocalMode()){ + try { + KettleDTO kettleDTO = new KettleDTO(); + kettleDTO.setCarte(env.getProperty("carte.host", "127.0.0.1")); + kettleDTO.setPort(env.getProperty("carte.port", "8080")); + kettleDTO.setUser(env.getProperty("carte.user", "cluster")); + kettleDTO.setPasswd(env.getProperty("carte.passwd", "cluster")); + validate(kettleDTO); + return true; + }catch (Exception e){ + return false; + } + } + if(engineService.isClusterMode()){ + List kettles = pageList().stream().filter(kettle -> kettle.getStatus() != null && kettle.getStatus().equalsIgnoreCase("Success")) + .collect(Collectors.toList()); + if(CollectionUtils.isEmpty(kettles)){ + return false; + }else { + return true; + } + } + return false; + } + +} diff --git a/backend/src/main/resources/db/migration/V33__1.9.sql b/backend/src/main/resources/db/migration/V33__1.9.sql index 6a1d66b0b3..7d70f7e67d 100644 --- a/backend/src/main/resources/db/migration/V33__1.9.sql +++ b/backend/src/main/resources/db/migration/V33__1.9.sql @@ -247,3 +247,4 @@ END ;; delimiter ; +INSERT INTO `my_plugin`(`plugin_id`, `name`, `store`, `free`, `cost`, `category`, `descript`, `version`, `install_type`, `creator`, `load_mybatis`, `release_time`, `install_time`, `module_name`, `icon`) VALUES (3, 'tabs插件', 'default', 0, 20000, 'panel', 'tabs插件', '1.0-SNAPSHOT', NULL, 'fit2cloud-chenyw', 0, NULL, NULL, 'dataease-extensions-tabs-backend', NULL); \ No newline at end of file diff --git a/frontend/src/api/system/kettle.js b/frontend/src/api/system/kettle.js new file mode 100644 index 0000000000..dc8ceea939 --- /dev/null +++ b/frontend/src/api/system/kettle.js @@ -0,0 +1,49 @@ +import request from '@/utils/request' +import {validateDs} from "@/api/system/datasource"; + + + +export function validate(data) { + return request({ + url: '/kettle/validate', + method: 'post', + loading: true, + data + }) +} + +export function validateById(id) { + return request({ + url: '/kettle/validate/' + id, + method: 'post', + loading: true + }) +} + +export function save(data) { + return request({ + url: '/kettle/save', + method: 'post', + loading: true, + data + }) +} + +export function deleteKettle(id) { + return request({ + url: '/delete/' + id, + method: 'delete', + loading: true + }) +} + + + +export function pageList(url, data) { + return request({ + url: url, + method: 'post', + loading: true, + data + }) +} diff --git a/frontend/src/components/AsyncSoltComponent/index.vue b/frontend/src/components/AsyncSoltComponent/index.vue new file mode 100644 index 0000000000..891e1a6900 --- /dev/null +++ b/frontend/src/components/AsyncSoltComponent/index.vue @@ -0,0 +1,76 @@ + + + diff --git a/frontend/src/components/canvas/components/TextAttr.vue b/frontend/src/components/canvas/components/TextAttr.vue index 13688f3b5d..94cdc24b5c 100644 --- a/frontend/src/components/canvas/components/TextAttr.vue +++ b/frontend/src/components/canvas/components/TextAttr.vue @@ -140,6 +140,12 @@ +
+ + + +
+ @@ -150,7 +156,6 @@ import Hyperlinks from '@/components/canvas/components/Editor/Hyperlinks' import VideoLinks from '@/components/canvas/components/Editor/VideoLinks' import DateFormat from '@/components/canvas/components/Editor/DateFormat' import { COLOR_PANEL } from '@/views/chart/chart/chart' -import { chartTransStr2Object } from '@/views/panel/panel' export default { components: { Hyperlinks, DateFormat, VideoLinks }, @@ -245,7 +250,8 @@ export default { 'borderWidth', 'borderRadius', 'opacity', - 'borderColor' + 'borderColor', + 'deTabStyle' ], // 矩形组件显示的属性 'rect-shape': [ @@ -416,6 +422,18 @@ export default { }, styleChange() { this.$store.commit('recordStyleChange') + }, + goHeadFontColor() { + this.$refs.headFontColorPicker.handleTrigger() + }, + goHeadFontActiveColor() { + this.$refs.headFontActiveColorPicker.handleTrigger() + }, + goHeadBorderColor() { + this.$refs.headBorderColorPicker.handleTrigger() + }, + goHeadBorderActiveColor() { + this.$refs.headBorderActiveColorPicker.handleTrigger() } } } @@ -448,7 +466,6 @@ export default { display: inline!important; } - ::v-deep input::-webkit-outer-spin-button, ::v-deep input::-webkit-inner-spin-button { -webkit-appearance: none !important; diff --git a/frontend/src/components/widget/DeWidget/DeTabs.vue b/frontend/src/components/widget/DeWidget/DeTabs.vue index 359fd7945b..94adcab6a3 100644 --- a/frontend/src/components/widget/DeWidget/DeTabs.vue +++ b/frontend/src/components/widget/DeWidget/DeTabs.vue @@ -1,6 +1,19 @@