diff --git a/Dockerfile b/Dockerfile index f5118e68fd..986319240f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -13,10 +13,11 @@ WORKDIR /opt/apps ADD core/core-backend/target/CoreApplication.jar /opt/apps/app.jar ADD de-xpack/xpack-permissions/target/xpack-permissions-$IMAGE_TAG.jar /opt/apps/xpack-permission.jar ADD de-xpack/xpack-base/target/xpack-base-$IMAGE_TAG.jar /opt/apps/xpack-base.jar +ADD de-xpack/xpack-sync/target/xpack-sync-$IMAGE_TAG.jar /opt/apps/xpack-sync.jar ENV JAVA_APP_JAR=/opt/apps/app.jar HEALTHCHECK --interval=15s --timeout=5s --retries=20 --start-period=30s CMD curl -f 127.0.0.1:8100 -CMD java -Xmx1024m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/opt/dataease2.0/logs/dump.hprof -Dloader.path=/opt/apps/xpack-permission.jar,/opt/apps/xpack-base.jar -jar /opt/apps/app.jar +CMD java -Xmx1024m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/opt/dataease2.0/logs/dump.hprof -Dloader.path=/opt/apps/xpack-permission.jar,/opt/apps/xpack-base.jar,/opt/apps/xpack-sync.jar -jar /opt/apps/app.jar diff --git a/core/core-backend/pom.xml b/core/core-backend/pom.xml index 1e43ec1d51..72a5f97b9e 100644 --- a/core/core-backend/pom.xml +++ b/core/core-backend/pom.xml @@ -23,6 +23,11 @@ api-permissions ${dataease.version} + + io.dataease + api-sync + ${dataease.version} + com.mysql mysql-connector-j diff --git a/core/core-backend/src/main/java/io/dataease/MybatisPlusGenerator.java b/core/core-backend/src/main/java/io/dataease/MybatisPlusGenerator.java index 51424d85aa..12bd3304f8 100644 --- a/core/core-backend/src/main/java/io/dataease/MybatisPlusGenerator.java +++ b/core/core-backend/src/main/java/io/dataease/MybatisPlusGenerator.java @@ -21,11 +21,11 @@ public class MybatisPlusGenerator { /** * 业务模块例如datasource,dataset,panel等 */ - private static final String busi = "visualization"; + private static final String busi = "template"; /** * 这是要生成代码的表名称 */ - private static final String TABLE_NAME = "visualization_watermark"; + private static final String TABLE_NAME = "visualization_template"; /** * 下面两个配置基本上不用动 diff --git a/core/core-backend/src/main/java/io/dataease/chart/manage/ChartDataManage.java b/core/core-backend/src/main/java/io/dataease/chart/manage/ChartDataManage.java index 7faaa1e829..0db9a5d4e9 100644 --- a/core/core-backend/src/main/java/io/dataease/chart/manage/ChartDataManage.java +++ b/core/core-backend/src/main/java/io/dataease/chart/manage/ChartDataManage.java @@ -1,6 +1,5 @@ package io.dataease.chart.manage; -import cn.hutool.core.collection.CollectionUtil; import io.dataease.api.chart.dto.*; import io.dataease.api.chart.request.ChartDrillRequest; import io.dataease.api.chart.request.ChartExtRequest; @@ -32,12 +31,13 @@ import io.dataease.system.manage.CorePermissionManage; import io.dataease.utils.BeanUtils; import io.dataease.utils.JsonUtil; import jakarta.annotation.Resource; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.MapUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; -import org.springframework.util.CollectionUtils; import java.math.BigDecimal; import java.math.RoundingMode; @@ -246,7 +246,7 @@ public class ChartDataManage { boolean hasParameters = false; List sqlVariables = datasetGroupManage.getSqlParams(Arrays.asList(view.getTableId())); - if (CollectionUtil.isNotEmpty(sqlVariables)) { + 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(); if (sqlVariables.stream().map(SqlVariableDetails::getId).collect(Collectors.toList()).contains(parameterId)) { @@ -1146,8 +1146,8 @@ public class ChartDataManage { getIndex += xAxis.size(); } if (StringUtils.equalsIgnoreCase(fieldType, "extStack")) { - int xAxisSize = CollectionUtil.size(view.getXAxis()); - int extSize = CollectionUtil.size(view.getXAxisExt()); + int xAxisSize = CollectionUtils.size(view.getXAxis()); + int extSize = CollectionUtils.size(view.getXAxisExt()); index += xAxisSize + extSize; getIndex += xAxisSize + extSize; } @@ -1326,7 +1326,7 @@ public class ChartDataManage { } public void saveChartViewFromVisualization(String checkData, Long sceneId, Map chartViewsInfo) { - if (!CollectionUtils.isEmpty(chartViewsInfo)) { + if (!MapUtils.isEmpty(chartViewsInfo)) { chartViewsInfo.forEach((key, chartViewDTO) -> { if (checkData.indexOf(chartViewDTO.getId() + "") > -1) { try { diff --git a/core/core-backend/src/main/java/io/dataease/chart/server/ChartDataServer.java b/core/core-backend/src/main/java/io/dataease/chart/server/ChartDataServer.java index edcd4f7759..3df134d2d6 100644 --- a/core/core-backend/src/main/java/io/dataease/chart/server/ChartDataServer.java +++ b/core/core-backend/src/main/java/io/dataease/chart/server/ChartDataServer.java @@ -1,6 +1,5 @@ package io.dataease.chart.server; -import cn.hutool.core.util.ArrayUtil; import io.dataease.api.chart.ChartDataApi; import io.dataease.api.chart.dto.ChartViewDTO; import io.dataease.api.chart.dto.ViewDetailField; @@ -15,18 +14,14 @@ import io.dataease.visualization.manage.VisualizationTemplateExtendDataManage; import jakarta.annotation.Resource; import jakarta.servlet.http.HttpServletResponse; import org.apache.commons.collections4.CollectionUtils; -import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; -import org.apache.poi.hssf.usermodel.HSSFClientAnchor; -import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.usermodel.*; import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.xssf.streaming.SXSSFWorkbook; -import org.springframework.util.Base64Utils; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; import java.util.Arrays; @@ -50,9 +45,9 @@ public class ChartDataServer implements ChartDataApi { public ChartViewDTO getData(ChartViewDTO chartViewDTO) throws Exception { try { // 从模板数据获取 - if(CommonConstants.VIEW_DATA_FROM.TEMPLATE.equalsIgnoreCase(chartViewDTO.getDataFrom())){ - return extendDataManage.getChartDataInfo(chartViewDTO.getId(),chartViewDTO); - }else{ + if (CommonConstants.VIEW_DATA_FROM.TEMPLATE.equalsIgnoreCase(chartViewDTO.getDataFrom())) { + return extendDataManage.getChartDataInfo(chartViewDTO.getId(), chartViewDTO); + } else { return chartDataManage.calcData(chartViewDTO); } } catch (Exception e) { @@ -85,7 +80,7 @@ public class ChartDataServer implements ChartDataApi { @Override public void innerExportDetails(ChartExcelRequest request, HttpServletResponse response) throws Exception { - OutputStream outputStream = response.getOutputStream(); + OutputStream outputStream = response.getOutputStream(); try { findExcelData(request); List details = request.getDetails(); @@ -114,7 +109,7 @@ public class ChartDataServer implements ChartDataApi { Boolean mergeHead = false; ViewDetailField[] detailFields = request.getDetailFields(); - if (ArrayUtil.isNotEmpty(detailFields)) { + if (ArrayUtils.isNotEmpty(detailFields)) { cellStyle.setBorderTop(BorderStyle.THIN); cellStyle.setBorderRight(BorderStyle.THIN); cellStyle.setBorderBottom(BorderStyle.THIN); @@ -199,7 +194,7 @@ public class ChartDataServer implements ChartDataApi { } else if (cellValObj != null) { try { // with DataType - if ((excelTypes[j].equals(DeTypeConstants.DE_INT) || excelTypes[j] .equals(DeTypeConstants.DE_FLOAT) ) && StringUtils.isNotEmpty(cellValObj.toString())) { + if ((excelTypes[j].equals(DeTypeConstants.DE_INT) || excelTypes[j].equals(DeTypeConstants.DE_FLOAT)) && StringUtils.isNotEmpty(cellValObj.toString())) { cell.setCellValue(Double.valueOf(cellValObj.toString())); } else { cell.setCellValue(cellValObj.toString()); diff --git a/core/core-backend/src/main/java/io/dataease/chart/utils/ChartDataBuild.java b/core/core-backend/src/main/java/io/dataease/chart/utils/ChartDataBuild.java index 7dfa8e7fe1..0e6f826ecc 100644 --- a/core/core-backend/src/main/java/io/dataease/chart/utils/ChartDataBuild.java +++ b/core/core-backend/src/main/java/io/dataease/chart/utils/ChartDataBuild.java @@ -1,8 +1,8 @@ package io.dataease.chart.utils; -import cn.hutool.core.util.ArrayUtil; import io.dataease.api.chart.dto.*; import io.dataease.utils.IDUtils; +import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; @@ -1004,7 +1004,7 @@ public class ChartDataBuild { Map map = transTableNormal(fields, null, data, desensitizationList); List> tableRow = (List>) map.get("tableRow"); final int xEndIndex = detailIndex; - Map> groupDataList = detailData.stream().collect(Collectors.groupingBy(item -> ArrayUtil.join(ArrayUtil.sub(item, 0, xEndIndex), "-de-", "(", ")"))); + Map> groupDataList = detailData.stream().collect(Collectors.groupingBy(item -> "(" + StringUtils.join(ArrayUtils.subarray(item, 0, xEndIndex), "-de-") + ")")); tableRow.forEach(row -> { String key = xAxis.stream().map(x -> String.format(format, row.get(x.getDataeaseName()).toString())).collect(Collectors.joining("-de-")); diff --git a/core/core-backend/src/main/java/io/dataease/commons/utils/SqlparserUtils.java b/core/core-backend/src/main/java/io/dataease/commons/utils/SqlparserUtils.java index eacb52d182..4b6ffc6c28 100644 --- a/core/core-backend/src/main/java/io/dataease/commons/utils/SqlparserUtils.java +++ b/core/core-backend/src/main/java/io/dataease/commons/utils/SqlparserUtils.java @@ -60,12 +60,13 @@ public class SqlparserUtils { } private static void getDependencies(SqlNode sqlNode, Boolean fromOrJoin) { - + if (sqlNode == null) { + return; + } if (sqlNode.getKind() == JOIN) { SqlJoin sqlKind = (SqlJoin) sqlNode; } else if (sqlNode.getKind() == IDENTIFIER) { - } else if (sqlNode.getKind() == AS) { SqlBasicCall sqlKind = (SqlBasicCall) sqlNode; } else if (sqlNode.getKind() == SELECT) { @@ -80,9 +81,19 @@ public class SqlparserUtils { SqlNode newWhere = sqlKind.getWhere().accept(getSqlShuttle()); sqlKind.setWhere(newWhere); } - - } else { - // TODO 这里可根据需求拓展处理其他类型的 sqlNode + } else if (sqlNode.getKind() == ORDER_BY) { + SqlOrderBy sqlKind = (SqlOrderBy) sqlNode; + List operandList = sqlKind.getOperandList(); + for (int i = 0; i < operandList.size(); i++) { + getDependencies(operandList.get(i), false); + } + } else if (sqlNode.getKind() == UNION) { + SqlBasicCall sqlKind = (SqlBasicCall) sqlNode; + if (sqlKind.getOperandList().size() >= 2) { + for (int i = 0; i < sqlKind.getOperandList().size(); i++) { + getDependencies(sqlKind.getOperandList().get(i), false); + } + } } } diff --git a/core/core-backend/src/main/java/io/dataease/dataset/manage/DatasetGroupManage.java b/core/core-backend/src/main/java/io/dataease/dataset/manage/DatasetGroupManage.java index 1258586555..cc81808666 100644 --- a/core/core-backend/src/main/java/io/dataease/dataset/manage/DatasetGroupManage.java +++ b/core/core-backend/src/main/java/io/dataease/dataset/manage/DatasetGroupManage.java @@ -1,6 +1,5 @@ package io.dataease.dataset.manage; -import cn.hutool.core.collection.CollectionUtil; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.fasterxml.jackson.core.type.TypeReference; import io.dataease.api.dataset.dto.DatasetTableDTO; @@ -32,6 +31,7 @@ import io.dataease.operation.manage.CoreOptRecentManage; import io.dataease.system.manage.CoreUserManage; import io.dataease.utils.*; import jakarta.annotation.Resource; +import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Component; @@ -211,7 +211,7 @@ public class DatasetGroupManage { List nodes = new ArrayList<>(); if (ObjectUtils.isEmpty(request.getLeaf()) || !request.getLeaf()) nodes.add(rootNode()); List bos = pos.stream().map(this::convert).toList(); - if (CollectionUtil.isNotEmpty(bos)) { + if (CollectionUtils.isNotEmpty(bos)) { nodes.addAll(bos); } return TreeUtils.mergeTree(nodes, BusiNodeVO.class, false); @@ -449,10 +449,11 @@ public class DatasetGroupManage { for (CoreDatasetTable datasetTable : datasetTables) { if (StringUtils.isNotEmpty(datasetTable.getSqlVariableDetails())) { List defaultsSqlVariableDetails = JsonUtil.parseList(datasetTable.getSqlVariableDetails(), listTypeReference); - if (CollectionUtil.isNotEmpty(defaultsSqlVariableDetails)) { + if (CollectionUtils.isNotEmpty(defaultsSqlVariableDetails)) { List fullName = new ArrayList<>(); geFullName(id, fullName); - List finalFullName = CollectionUtil.reverse(fullName); + Collections.reverse(fullName); + List finalFullName = fullName; defaultsSqlVariableDetails.forEach(sqlVariableDetails -> { sqlVariableDetails.setDatasetGroupId(id); sqlVariableDetails.setDatasetTableId(datasetTable.getId()); @@ -500,13 +501,13 @@ public class DatasetGroupManage { public List getDetailWithPerm(List ids) { var result = new ArrayList(); - if (CollectionUtil.isNotEmpty(ids)) { + if (CollectionUtils.isNotEmpty(ids)) { var dsList = coreDatasetGroupMapper.selectBatchIds(ids); - if (CollectionUtil.isNotEmpty(dsList)) { + if (CollectionUtils.isNotEmpty(dsList)) { dsList.forEach(ds -> { DatasetTableDTO dto = new DatasetTableDTO(); BeanUtils.copyBean(dto, ds); - var fields = datasetTableFieldManage.listFieldsWithPermissions(ds.getId()); + var fields = datasetTableFieldManage.listFieldsWithPermissions(ds.getId()); List dimensionList = fields.stream().filter(ele -> StringUtils.equalsIgnoreCase(ele.getGroupType(), "d")).toList(); List quotaList = fields.stream().filter(ele -> StringUtils.equalsIgnoreCase(ele.getGroupType(), "q")).toList(); Map> map = new LinkedHashMap<>(); diff --git a/core/core-backend/src/main/java/io/dataease/dataset/manage/DatasetTableFieldManage.java b/core/core-backend/src/main/java/io/dataease/dataset/manage/DatasetTableFieldManage.java index 08bf01ada9..2266e16989 100644 --- a/core/core-backend/src/main/java/io/dataease/dataset/manage/DatasetTableFieldManage.java +++ b/core/core-backend/src/main/java/io/dataease/dataset/manage/DatasetTableFieldManage.java @@ -1,9 +1,7 @@ package io.dataease.dataset.manage; -import cn.hutool.core.collection.CollUtil; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import io.dataease.api.chart.dto.ColumnPermissionItem; -import io.dataease.auth.bo.TokenUserBO; import io.dataease.dataset.dao.auto.entity.CoreDatasetTableField; import io.dataease.dataset.dao.auto.mapper.CoreDatasetGroupMapper; import io.dataease.dataset.dao.auto.mapper.CoreDatasetTableFieldMapper; diff --git a/core/core-backend/src/main/java/io/dataease/datasource/manage/DataSourceManage.java b/core/core-backend/src/main/java/io/dataease/datasource/manage/DataSourceManage.java index a26fe93b95..8b0da25485 100644 --- a/core/core-backend/src/main/java/io/dataease/datasource/manage/DataSourceManage.java +++ b/core/core-backend/src/main/java/io/dataease/datasource/manage/DataSourceManage.java @@ -1,6 +1,5 @@ package io.dataease.datasource.manage; -import cn.hutool.core.collection.CollectionUtil; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import io.dataease.api.ds.vo.DatasourceDTO; @@ -19,6 +18,7 @@ import io.dataease.operation.manage.CoreOptRecentManage; import io.dataease.utils.AuthUtils; import io.dataease.utils.TreeUtils; import jakarta.annotation.Resource; +import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Component; @@ -65,7 +65,7 @@ public class DataSourceManage { List nodes = new ArrayList<>(); List pos = dataSourceExtMapper.selectList(queryWrapper); if (ObjectUtils.isEmpty(request.getLeaf()) || !request.getLeaf()) nodes.add(rootNode()); - if (CollectionUtil.isNotEmpty(pos)) { + if (CollectionUtils.isNotEmpty(pos)) { nodes.addAll(pos.stream().map(this::convert).toList()); } return TreeUtils.mergeTree(nodes, BusiNodeVO.class, false); diff --git a/core/core-backend/src/main/java/io/dataease/datasource/provider/CalciteProvider.java b/core/core-backend/src/main/java/io/dataease/datasource/provider/CalciteProvider.java index 43438cb658..797bc92009 100644 --- a/core/core-backend/src/main/java/io/dataease/datasource/provider/CalciteProvider.java +++ b/core/core-backend/src/main/java/io/dataease/datasource/provider/CalciteProvider.java @@ -173,7 +173,7 @@ public class CalciteProvider { datasetTableFields.add(tableField); } list = getDataResult(resultSet); - } catch (Exception e) { + } catch (Exception | AssertionError e) { DEException.throwException(Translator.get("i18n_fetch_error") + e.getMessage()); } finally { try { @@ -255,7 +255,7 @@ public class CalciteProvider { DatasourceConfiguration configuration = null; DatasourceType datasourceType = DatasourceType.valueOf(ds.getType()); try { - if(rootSchema.getSubSchema(ds.getSchemaAlias()) != null){ + if (rootSchema.getSubSchema(ds.getSchemaAlias()) != null) { JdbcSchema jdbcSchema = rootSchema.getSubSchema(ds.getSchemaAlias()).unwrap(JdbcSchema.class); BasicDataSource basicDataSource = (BasicDataSource) jdbcSchema.getDataSource(); basicDataSource.close(); diff --git a/core/core-backend/src/main/java/io/dataease/datasource/server/DatasourceServer.java b/core/core-backend/src/main/java/io/dataease/datasource/server/DatasourceServer.java index 7296453e33..ee875b83aa 100644 --- a/core/core-backend/src/main/java/io/dataease/datasource/server/DatasourceServer.java +++ b/core/core-backend/src/main/java/io/dataease/datasource/server/DatasourceServer.java @@ -1,6 +1,5 @@ package io.dataease.datasource.server; -import cn.hutool.core.collection.CollectionUtil; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; @@ -42,13 +41,13 @@ import io.dataease.system.dao.auto.entity.CoreSysSetting; import io.dataease.system.manage.CoreUserManage; import io.dataease.utils.*; import jakarta.annotation.Resource; +import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.quartz.JobDataMap; import org.quartz.JobKey; import org.quartz.TriggerKey; import org.springframework.transaction.annotation.Transactional; -import org.springframework.util.CollectionUtils; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; @@ -137,6 +136,9 @@ public class DatasourceServer implements DatasourceApi { dataSourceManage.move(dataSourceDTO); } case "rename" -> { + if(StringUtils.isEmpty(dataSourceDTO.getName())){ + DEException.throwException("名称不能为空!"); + } CoreDatasource datasource = datasourceMapper.selectById(dataSourceDTO.getId()); datasource.setName(dataSourceDTO.getName()); dataSourceManage.innerEdit(datasource); @@ -168,7 +170,7 @@ public class DatasourceServer implements DatasourceApi { ids.add(busiNodeVO.getId()); } } - if (CollectionUtil.isNotEmpty(busiNodeVO.getChildren())) { + if (CollectionUtils.isNotEmpty(busiNodeVO.getChildren())) { filterDs(busiNodeVO.getChildren(), ids, type, id); } } @@ -184,14 +186,14 @@ public class DatasourceServer implements DatasourceApi { List ids = new ArrayList<>(); filterDs(busiNodeVOS, ids, dataSourceDTO.getType(), dataSourceDTO.getId()); - if (CollectionUtil.isEmpty(ids)) { + if (CollectionUtils.isEmpty(ids)) { return false; } QueryWrapper wrapper = new QueryWrapper<>(); wrapper.in("id", ids); List datasources = datasourceMapper.selectList(wrapper); - if (CollectionUtil.isEmpty(datasources)) { + if (CollectionUtils.isEmpty(datasources)) { return false; } dataSourceDTO.setConfiguration(new String(Base64.getDecoder().decode(dataSourceDTO.getConfiguration()))); @@ -465,8 +467,9 @@ public class DatasourceServer implements DatasourceApi { CoreDatasource coreDatasource = new CoreDatasource(); BeanUtils.copyBean(coreDatasource, dataSourceDTO); checkDatasourceStatus(coreDatasource); - dataSourceDTO.setStatus(coreDatasource.getStatus()); - return dataSourceDTO; + DatasourceDTO result = new DatasourceDTO(); + result.setStatus(coreDatasource.getStatus()); + return result; } @Override diff --git a/core/core-backend/src/main/java/io/dataease/map/manage/MapManage.java b/core/core-backend/src/main/java/io/dataease/map/manage/MapManage.java index b49278b60b..a5dcb5efef 100644 --- a/core/core-backend/src/main/java/io/dataease/map/manage/MapManage.java +++ b/core/core-backend/src/main/java/io/dataease/map/manage/MapManage.java @@ -1,7 +1,5 @@ package io.dataease.map.manage; -import cn.hutool.core.collection.ListUtil; -import cn.hutool.core.io.FileUtil; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import io.dataease.api.map.dto.GeometryNodeCreator; import io.dataease.api.map.vo.AreaNode; @@ -14,6 +12,7 @@ import io.dataease.map.dao.ext.entity.CoreAreaCustom; import io.dataease.map.dao.ext.mapper.CoreAreaCustomMapper; import io.dataease.utils.BeanUtils; import io.dataease.utils.CommonBeanFactory; +import io.dataease.utils.FileUtils; import io.dataease.utils.LogUtil; import jakarta.annotation.Resource; import org.apache.commons.collections4.CollectionUtils; @@ -32,7 +31,6 @@ import java.util.HashMap; import java.util.List; import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; -import java.util.stream.Stream; import static io.dataease.constant.CacheConstant.CommonCacheConstant.WORLD_MAP_CACHE; @@ -114,7 +112,8 @@ public class MapManage { if (ObjectUtils.isEmpty(file) || file.isEmpty()) { DEException.throwException("geometry file is require"); } - String suffix = FileUtil.getSuffix(file.getOriginalFilename()); + + String suffix = FileUtils.getExtensionName(file.getOriginalFilename()); if (!StringUtils.equalsIgnoreCase("json", suffix)) { DEException.throwException("仅支持json格式文件"); } @@ -164,7 +163,7 @@ public class MapManage { } List codeResultList = new ArrayList<>(); codeResultList.add(code); - childTreeIdList(ListUtil.of(code), codeResultList); + childTreeIdList(List.of(code), codeResultList); coreAreaCustomMapper.deleteBatchIds(codeResultList); codeResultList.forEach(id -> { File file = buildGeoFile(id); diff --git a/core/core-backend/src/main/java/io/dataease/menu/manage/MenuManage.java b/core/core-backend/src/main/java/io/dataease/menu/manage/MenuManage.java index b5434e11c9..f5e3296bfa 100644 --- a/core/core-backend/src/main/java/io/dataease/menu/manage/MenuManage.java +++ b/core/core-backend/src/main/java/io/dataease/menu/manage/MenuManage.java @@ -1,6 +1,5 @@ package io.dataease.menu.manage; -import cn.hutool.core.collection.CollectionUtil; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import io.dataease.api.menu.vo.MenuMeta; import io.dataease.api.menu.vo.MenuVO; @@ -10,6 +9,7 @@ import io.dataease.menu.dao.auto.entity.CoreMenu; import io.dataease.menu.dao.auto.mapper.CoreMenuMapper; import io.dataease.utils.BeanUtils; import jakarta.annotation.Resource; +import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Component; @@ -61,10 +61,10 @@ public class MenuManage { for (MenuTreeNode menuTreeNode : roots) { MenuVO vo = convert(menuTreeNode); List children = null; - if (CollectionUtil.isNotEmpty(children = menuTreeNode.getChildren())) { + if (CollectionUtils.isNotEmpty(children = menuTreeNode.getChildren())) { vo.setChildren(convertTree(children)); } - if (CollectionUtil.isNotEmpty(vo.getChildren()) || menuTreeNode.getType() != 1) { + if (CollectionUtils.isNotEmpty(vo.getChildren()) || menuTreeNode.getType() != 1) { result.add(vo); } } diff --git a/core/core-backend/src/main/java/io/dataease/operation/manage/CoreOptRecentManage.java b/core/core-backend/src/main/java/io/dataease/operation/manage/CoreOptRecentManage.java index ff332a523e..f9e8283684 100644 --- a/core/core-backend/src/main/java/io/dataease/operation/manage/CoreOptRecentManage.java +++ b/core/core-backend/src/main/java/io/dataease/operation/manage/CoreOptRecentManage.java @@ -1,12 +1,12 @@ package io.dataease.operation.manage; -import cn.hutool.core.collection.CollectionUtil; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import io.dataease.commons.constants.OptConstants; import io.dataease.operation.dao.auto.entity.CoreOptRecent; import io.dataease.operation.dao.auto.mapper.CoreOptRecentMapper; import io.dataease.utils.AuthUtils; import io.dataease.utils.IDUtils; +import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -64,7 +64,7 @@ public class CoreOptRecentManage { queryWrapper.eq("resource_type", OptConstants.OPT_RESOURCE_TYPE.TEMPLATE); queryWrapper.eq("uid", uid); List result = coreStoreMapper.selectList(queryWrapper); - if (CollectionUtil.isNotEmpty(result)) { + if (CollectionUtils.isNotEmpty(result)) { return result.stream().collect(Collectors.toMap(CoreOptRecent::getResourceName, CoreOptRecent::getTime)); } else { return new HashMap<>(); diff --git a/core/core-backend/src/main/java/io/dataease/rmonitor/bo/PerMonitorCheckBO.java b/core/core-backend/src/main/java/io/dataease/rmonitor/bo/PerMonitorCheckBO.java new file mode 100644 index 0000000000..aab6e1ed4e --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/rmonitor/bo/PerMonitorCheckBO.java @@ -0,0 +1,12 @@ +package io.dataease.rmonitor.bo; + +import lombok.Data; +import java.io.Serializable; + +@Data +public class PerMonitorCheckBO implements Serializable { + + private boolean valid; + + private boolean emptyPermission; +} diff --git a/core/core-backend/src/main/java/io/dataease/rmonitor/bo/PerMonitorNodeBO.java b/core/core-backend/src/main/java/io/dataease/rmonitor/bo/PerMonitorNodeBO.java new file mode 100644 index 0000000000..ea2e91720c --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/rmonitor/bo/PerMonitorNodeBO.java @@ -0,0 +1,24 @@ +package io.dataease.rmonitor.bo; + +import io.dataease.model.TreeBaseModel; +import io.dataease.model.TreeResultModel; +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +@Data +public class PerMonitorNodeBO implements TreeBaseModel, TreeResultModel, Serializable { + + private Long id; + + private String name; + + private Long pid; + + private boolean leaf; + + private int extraFlag; + + private List children; +} diff --git a/core/core-backend/src/main/java/io/dataease/rmonitor/manage/ResourceMonitorManage.java b/core/core-backend/src/main/java/io/dataease/rmonitor/manage/ResourceMonitorManage.java new file mode 100644 index 0000000000..920e90cd3b --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/rmonitor/manage/ResourceMonitorManage.java @@ -0,0 +1,118 @@ +package io.dataease.rmonitor.manage; + +import io.dataease.exception.DEException; +import io.dataease.rmonitor.bo.PerMonitorCheckBO; +import io.dataease.rmonitor.bo.PerMonitorNodeBO; +import io.dataease.rmonitor.mapper.ResourceMonitorMapper; +import io.dataease.rmonitor.mapper.entity.DatasetFreeResource; +import io.dataease.rmonitor.mapper.entity.DsFreeResource; +import io.dataease.rmonitor.mapper.entity.VisualFreeResource; +import io.dataease.utils.BeanUtils; +import io.dataease.utils.TreeUtils; +import jakarta.annotation.Resource; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Component("resourceMonitorManage") +public class ResourceMonitorManage { + + + @Resource(name = "resourceMonitorSyncManage") + private ResourceMonitorSyncManage resourceMonitorSyncManage; + + @Resource + private ResourceMonitorMapper resourceMonitorMapper; + + + private boolean existFreeResource() { + int rCount = resourceMonitorMapper.dsCount() + resourceMonitorMapper.datasetCount() + resourceMonitorMapper.vCount(); + return rCount > 0; + } + + private Map> freeResource() { + Map> result = new HashMap<>(); + + List dsFreeResources = resourceMonitorMapper.queryFreeDs(); + if (CollectionUtils.isNotEmpty(dsFreeResources)) { + List dsBos = dsFreeResources.stream().map(node -> { + PerMonitorNodeBO bo = BeanUtils.copyBean(new PerMonitorNodeBO(), node); + bo.setLeaf(StringUtils.equals("folder", node.getType())); + return bo; + }).collect(Collectors.toList()); + List dsTree = TreeUtils.mergeTree(dsBos, PerMonitorNodeBO.class, false); + result.put("datasource", dsTree); + } + + List datasetFreeResources = resourceMonitorMapper.queryFreeDataset(); + if (CollectionUtils.isNotEmpty(datasetFreeResources)) { + List datasetBos = datasetFreeResources.stream().map(node -> { + PerMonitorNodeBO bo = BeanUtils.copyBean(new PerMonitorNodeBO(), node); + bo.setLeaf(StringUtils.equals("folder", node.getNodeType())); + return bo; + }).collect(Collectors.toList()); + List datasetTree = TreeUtils.mergeTree(datasetBos, PerMonitorNodeBO.class, false); + result.put("dataset", datasetTree); + } + + List visualFreeResources = resourceMonitorMapper.queryFreeVusial(); + if (CollectionUtils.isNotEmpty(visualFreeResources)) { + Map> baseMap = visualFreeResources.stream().collect(Collectors.groupingBy(VisualFreeResource::getType)); + for (Map.Entry> entry : baseMap.entrySet()) { + List freeResource = entry.getValue(); + List visualBos = freeResource.stream().map(node -> { + PerMonitorNodeBO bo = BeanUtils.copyBean(new PerMonitorNodeBO(), node); + bo.setLeaf(StringUtils.equals("folder", node.getNodeType())); + return bo; + }).collect(Collectors.toList()); + result.put(convertBusiFlag(entry.getKey()), TreeUtils.mergeTree(visualBos, PerMonitorNodeBO.class, false)); + } + } + return result; + } + + private String convertBusiFlag(String key) { + if (StringUtils.equals("dashboard", key)){ + return "panel"; + } else if (StringUtils.equals("dataV", key)) { + return "screen"; + } else return key; + } + + public boolean check() { + PerMonitorCheckBO checkBO = resourceMonitorSyncManage.checkXpackResource(); + return checkBO.isValid() && checkBO.isEmptyPermission() && existFreeResource(); + } + + @Transactional + public void delete() { + boolean existFree = existFreeResource(); + if (!existFree) DEException.throwException("无未同步资源!"); + resourceMonitorMapper.delFreeDs(); + resourceMonitorMapper.delFreeDataset(); + resourceMonitorMapper.delFreeVisual(); + } + + public void sync() { + //1、从xpack获取资源 如果xpack不存在 或者资源不为空 则直接返回 并且抛出异常“仅支持首次导入lic同步” + //2、从core获取资源 + //3、根据类型分组 并组织成树形结构 + //4、分别遍历每一棵树 从上到下 同步到权限体系 给默认组织 + PerMonitorCheckBO checkBO = resourceMonitorSyncManage.checkXpackResource(); + if (!checkBO.isValid()) DEException.throwException("缺少许可证"); + if (!checkBO.isEmptyPermission()) DEException.throwException("仅支持license首次导入同步"); + Map> freeResourceMap = freeResource(); + if (MapUtils.isEmpty(freeResourceMap)) DEException.throwException("无未同步资源!"); + for (Map.Entry> entry : freeResourceMap.entrySet()) { + resourceMonitorSyncManage.sync(entry.getKey(), entry.getValue()); + } + } + +} diff --git a/core/core-backend/src/main/java/io/dataease/rmonitor/manage/ResourceMonitorSyncManage.java b/core/core-backend/src/main/java/io/dataease/rmonitor/manage/ResourceMonitorSyncManage.java new file mode 100644 index 0000000000..dc875acded --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/rmonitor/manage/ResourceMonitorSyncManage.java @@ -0,0 +1,28 @@ +package io.dataease.rmonitor.manage; + +import io.dataease.exception.DEException; +import io.dataease.license.config.XpackInteract; +import io.dataease.rmonitor.bo.PerMonitorCheckBO; +import io.dataease.rmonitor.bo.PerMonitorNodeBO; +import io.dataease.rmonitor.mapper.ResourceMonitorMapper; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Component; + +import java.util.List; + +@Component("resourceMonitorSyncManage") +public class ResourceMonitorSyncManage { + + @Resource(name = "resourceMonitorMapper") + private ResourceMonitorMapper resourceMonitorMapper; + + @XpackInteract(value = "resourceMonitorSyncManage", replace = true) + public void sync(String flag, List treeNodes) { + DEException.throwException("缺失许可证"); + } + + @XpackInteract(value = "resourceMonitorSyncManage", replace = true) + public PerMonitorCheckBO checkXpackResource() { + return new PerMonitorCheckBO(); + } +} diff --git a/core/core-backend/src/main/java/io/dataease/rmonitor/mapper/ResourceMonitorMapper.java b/core/core-backend/src/main/java/io/dataease/rmonitor/mapper/ResourceMonitorMapper.java new file mode 100644 index 0000000000..0b2ae83575 --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/rmonitor/mapper/ResourceMonitorMapper.java @@ -0,0 +1,41 @@ +package io.dataease.rmonitor.mapper; + +import io.dataease.rmonitor.mapper.entity.DatasetFreeResource; +import io.dataease.rmonitor.mapper.entity.DsFreeResource; +import io.dataease.rmonitor.mapper.entity.VisualFreeResource; +import org.apache.ibatis.annotations.Delete; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Select; + +import java.util.List; + +@Mapper +public interface ResourceMonitorMapper { + + @Select("select count(id) from core_datasource") + int dsCount(); + + @Select("select count(id) from core_dataset_group") + int datasetCount(); + + @Select("select count(id) from data_visualization_info") + int vCount(); + + @Select("select id, name, pid, type, status from core_datasource") + List queryFreeDs(); + + @Select("select id, name, pid, node_type from core_dataset_group") + List queryFreeDataset(); + + @Select("select id, name, pid, node_type, type from data_visualization_info") + List queryFreeVusial(); + + @Delete("delete from core_datasource") + void delFreeDs(); + + @Delete("delete from core_dataset_group") + void delFreeDataset(); + @Delete("delete from data_visualization_info") + void delFreeVisual(); + +} diff --git a/core/core-backend/src/main/java/io/dataease/rmonitor/mapper/entity/BaseFreeResource.java b/core/core-backend/src/main/java/io/dataease/rmonitor/mapper/entity/BaseFreeResource.java new file mode 100644 index 0000000000..390acb6e10 --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/rmonitor/mapper/entity/BaseFreeResource.java @@ -0,0 +1,15 @@ +package io.dataease.rmonitor.mapper.entity; + +import lombok.Data; + +import java.io.Serializable; + +@Data +public class BaseFreeResource implements Serializable { + + private Long id; + + private String name; + + private Long pid; +} diff --git a/core/core-backend/src/main/java/io/dataease/rmonitor/mapper/entity/DatasetFreeResource.java b/core/core-backend/src/main/java/io/dataease/rmonitor/mapper/entity/DatasetFreeResource.java new file mode 100644 index 0000000000..1d4f85c00a --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/rmonitor/mapper/entity/DatasetFreeResource.java @@ -0,0 +1,13 @@ +package io.dataease.rmonitor.mapper.entity; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; + +@EqualsAndHashCode(callSuper = true) +@Data +public class DatasetFreeResource extends BaseFreeResource implements Serializable { + + private String nodeType; +} diff --git a/core/core-backend/src/main/java/io/dataease/rmonitor/mapper/entity/DsFreeResource.java b/core/core-backend/src/main/java/io/dataease/rmonitor/mapper/entity/DsFreeResource.java new file mode 100644 index 0000000000..a8dc0fd1a0 --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/rmonitor/mapper/entity/DsFreeResource.java @@ -0,0 +1,16 @@ +package io.dataease.rmonitor.mapper.entity; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; + +@EqualsAndHashCode(callSuper = true) +@Data +public class DsFreeResource extends BaseFreeResource implements Serializable { + + private String type; + + private String status; + +} diff --git a/core/core-backend/src/main/java/io/dataease/rmonitor/mapper/entity/VisualFreeResource.java b/core/core-backend/src/main/java/io/dataease/rmonitor/mapper/entity/VisualFreeResource.java new file mode 100644 index 0000000000..d3302b84c5 --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/rmonitor/mapper/entity/VisualFreeResource.java @@ -0,0 +1,15 @@ +package io.dataease.rmonitor.mapper.entity; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; + +@EqualsAndHashCode(callSuper = true) +@Data +public class VisualFreeResource extends BaseFreeResource implements Serializable { + + private String nodeType; + + private String type; +} diff --git a/core/core-backend/src/main/java/io/dataease/rmonitor/server/ResourceMonitorServer.java b/core/core-backend/src/main/java/io/dataease/rmonitor/server/ResourceMonitorServer.java new file mode 100644 index 0000000000..1289ba3a79 --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/rmonitor/server/ResourceMonitorServer.java @@ -0,0 +1,30 @@ +package io.dataease.rmonitor.server; + +import io.dataease.api.rmonitor.ResourceMonitorApi; +import io.dataease.rmonitor.manage.ResourceMonitorManage; +import jakarta.annotation.Resource; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/rmonitor") +public class ResourceMonitorServer implements ResourceMonitorApi { + + @Resource(name = "resourceMonitorManage") + private ResourceMonitorManage resourceMonitorManage; + + @Override + public boolean existFree() { + return resourceMonitorManage.check(); + } + + @Override + public void delete() { + resourceMonitorManage.delete(); + } + + @Override + public void sync() { + resourceMonitorManage.sync(); + } +} diff --git a/core/core-backend/src/main/java/io/dataease/share/dao/auto/entity/XpackShare.java b/core/core-backend/src/main/java/io/dataease/share/dao/auto/entity/XpackShare.java new file mode 100644 index 0000000000..2ea358f8ae --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/share/dao/auto/entity/XpackShare.java @@ -0,0 +1,150 @@ +package io.dataease.share.dao.auto.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import java.io.Serializable; + +/** + * + * + * + * + * @author fit2cloud + * @since 2023-09-22 + */ +@TableName("xpack_share") +public class XpackShare implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * ID + */ + private Long id; + + /** + * 创建人 + */ + private Long creator; + + /** + * 创建时间 + */ + private Long time; + + /** + * 过期时间 + */ + private Long exp; + + /** + * uuid + */ + private String uuid; + + /** + * 密码 + */ + private String pwd; + + /** + * 资源ID + */ + private Long resourceId; + + /** + * 组织ID + */ + private Long oid; + + /** + * 业务类型 + */ + private Integer type; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getCreator() { + return creator; + } + + public void setCreator(Long creator) { + this.creator = creator; + } + + public Long getTime() { + return time; + } + + public void setTime(Long time) { + this.time = time; + } + + public Long getExp() { + return exp; + } + + public void setExp(Long exp) { + this.exp = exp; + } + + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + public String getPwd() { + return pwd; + } + + public void setPwd(String pwd) { + this.pwd = pwd; + } + + public Long getResourceId() { + return resourceId; + } + + public void setResourceId(Long resourceId) { + this.resourceId = resourceId; + } + + public Long getOid() { + return oid; + } + + public void setOid(Long oid) { + this.oid = oid; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + @Override + public String toString() { + return "XpackShare{" + + "id = " + id + + ", creator = " + creator + + ", time = " + time + + ", exp = " + exp + + ", uuid = " + uuid + + ", pwd = " + pwd + + ", resourceId = " + resourceId + + ", oid = " + oid + + ", type = " + type + + "}"; + } +} diff --git a/core/core-backend/src/main/java/io/dataease/share/dao/auto/mapper/XpackShareMapper.java b/core/core-backend/src/main/java/io/dataease/share/dao/auto/mapper/XpackShareMapper.java new file mode 100644 index 0000000000..488a2acc43 --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/share/dao/auto/mapper/XpackShareMapper.java @@ -0,0 +1,18 @@ +package io.dataease.share.dao.auto.mapper; + +import io.dataease.share.dao.auto.entity.XpackShare; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; + +/** + * + * Mapper 接口 + * + * + * @author fit2cloud + * @since 2023-09-22 + */ +@Mapper +public interface XpackShareMapper extends BaseMapper { + +} diff --git a/core/core-backend/src/main/java/io/dataease/share/dao/ext/mapper/XpackShareExtMapper.java b/core/core-backend/src/main/java/io/dataease/share/dao/ext/mapper/XpackShareExtMapper.java new file mode 100644 index 0000000000..4b122e87b7 --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/share/dao/ext/mapper/XpackShareExtMapper.java @@ -0,0 +1,30 @@ +package io.dataease.share.dao.ext.mapper; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import io.dataease.share.dao.ext.po.XpackSharePO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +@Mapper +public interface XpackShareExtMapper { + + @Select(""" + select + s.id as share_id, + v.id as resource_id, + v.type, + s.creator, + s.time, + s.exp, + v.name + from xpack_share s + left join data_visualization_info v on s.resource_id = v.id + ${ew.customSqlSegment} + """) + IPage query(IPage page, @Param("ew") QueryWrapper ew); + + @Select("select type from data_visualization_info where id = #{id}") + String visualizationType(@Param("id") Long id); +} diff --git a/core/core-backend/src/main/java/io/dataease/share/dao/ext/po/XpackSharePO.java b/core/core-backend/src/main/java/io/dataease/share/dao/ext/po/XpackSharePO.java new file mode 100644 index 0000000000..9b89fb7b03 --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/share/dao/ext/po/XpackSharePO.java @@ -0,0 +1,31 @@ +package io.dataease.share.dao.ext.po; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serial; +import java.io.Serializable; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class XpackSharePO implements Serializable { + @Serial + private static final long serialVersionUID = 7929343371768885789L; + + private Long shareId; + + private Long resourceId; + + private String name; + + private String type; + + private Long creator; + + private Long time; + + private Long exp; + +} diff --git a/core/core-backend/src/main/java/io/dataease/share/manage/XpackShareManage.java b/core/core-backend/src/main/java/io/dataease/share/manage/XpackShareManage.java new file mode 100644 index 0000000000..c325161e67 --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/share/manage/XpackShareManage.java @@ -0,0 +1,201 @@ +package io.dataease.share.manage; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import io.dataease.api.visualization.request.VisualizationWorkbranchQueryRequest; +import io.dataease.api.xpack.share.request.XpackShareProxyRequest; +import io.dataease.api.xpack.share.request.XpackSharePwdValidator; +import io.dataease.api.xpack.share.vo.XpackShareGridVO; +import io.dataease.api.xpack.share.vo.XpackShareProxyVO; +import io.dataease.auth.bo.TokenUserBO; +import io.dataease.constant.AuthConstant; +import io.dataease.constant.BusiResourceEnum; +import io.dataease.exception.DEException; +import io.dataease.license.config.XpackInteract; +import io.dataease.share.dao.auto.mapper.XpackShareMapper; +import io.dataease.utils.*; +import io.dataease.share.dao.auto.entity.XpackShare; +import io.dataease.share.dao.ext.mapper.XpackShareExtMapper; +import io.dataease.share.dao.ext.po.XpackSharePO; +import io.dataease.share.util.LinkTokenUtil; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.RandomStringUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Component("xpackShareManage") +public class XpackShareManage { + + @Resource(name = "xpackShareMapper") + private XpackShareMapper xpackShareMapper; + + @Resource(name = "xpackShareExtMapper") + private XpackShareExtMapper xpackShareExtMapper; + + public XpackShare queryByResource(Long resourceId) { + Long userId = AuthUtils.getUser().getUserId(); + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("creator", userId); + queryWrapper.eq("resource_id", resourceId); + return xpackShareMapper.selectOne(queryWrapper); + } + + public void switcher(Long resourceId) { + XpackShare originData = queryByResource(resourceId); + if (ObjectUtils.isNotEmpty(originData)) { + xpackShareMapper.deleteById(originData.getId()); + return; + } + TokenUserBO user = AuthUtils.getUser(); + Long userId = user.getUserId(); + XpackShare xpackShare = new XpackShare(); + xpackShare.setId(IDUtils.snowID()); + xpackShare.setCreator(userId); + xpackShare.setTime(System.currentTimeMillis()); + xpackShare.setResourceId(resourceId); + xpackShare.setUuid(RandomStringUtils.randomAlphanumeric(8)); + xpackShare.setOid(user.getDefaultOid()); + String dType = xpackShareExtMapper.visualizationType(resourceId); + xpackShare.setType(StringUtils.equalsIgnoreCase("dataV", dType) ? 2 : 1); + xpackShareMapper.insert(xpackShare); + } + + public void editExp(Long resourceId, Long exp) { + XpackShare originData = queryByResource(resourceId); + if (ObjectUtils.isEmpty(originData)) { + DEException.throwException("share instance not exist"); + } + originData.setExp(exp); + if (ObjectUtils.isEmpty(exp)) { + originData.setExp(0L); + } + xpackShareMapper.updateById(originData); + } + + public void editPwd(Long resourceId, String pwd) { + XpackShare originData = queryByResource(resourceId); + if (ObjectUtils.isEmpty(originData)) { + DEException.throwException("share instance not exist"); + } + originData.setPwd(pwd); + xpackShareMapper.updateById(originData); + } + + public IPage querySharePage(int goPage, int pageSize, VisualizationWorkbranchQueryRequest request) { + Long uid = AuthUtils.getUser().getUserId(); + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("s.creator", uid); + if (StringUtils.isNotBlank(request.getType())) { + BusiResourceEnum busiResourceEnum = BusiResourceEnum.valueOf(request.getType().toUpperCase()); + if (ObjectUtils.isEmpty(busiResourceEnum)) { + DEException.throwException("type is invalid"); + } + String resourceType = convertResourceType(request.getType()); + if (StringUtils.isNotBlank(resourceType)) { + queryWrapper.eq("v.type", resourceType); + } + } + if (StringUtils.isNotBlank(request.getKeyword())) { + queryWrapper.like("v.name", request.getKeyword()); + } + queryWrapper.orderBy(true, request.isAsc(), "s.time"); + Page page = new Page<>(goPage, pageSize); + return xpackShareExtMapper.query(page, queryWrapper); + } + + private String convertResourceType(String busiFlag) { + return switch (busiFlag) { + case "panel" -> "dashboard"; + case "screen" -> "dataV"; + default -> null; + }; + } + + @XpackInteract(value = "perFilterShareManage", recursion = true) + public IPage query(int pageNum, int pageSize, VisualizationWorkbranchQueryRequest request) { + IPage poiPage = proxy().querySharePage(pageNum, pageSize, request); + List vos = proxy().formatResult(poiPage.getRecords()); + IPage ipage = new Page<>(); + ipage.setSize(poiPage.getSize()); + ipage.setCurrent(poiPage.getCurrent()); + ipage.setPages(poiPage.getPages()); + ipage.setTotal(poiPage.getTotal()); + ipage.setRecords(vos); + return ipage; + } + + public List formatResult(List pos) { + if (CollectionUtils.isEmpty(pos)) return new ArrayList<>(); + return pos.stream().map(po -> + new XpackShareGridVO( + po.getShareId(), po.getResourceId(), po.getName(), po.getCreator().toString(), + po.getTime(), po.getExp(), 9)).toList(); + } + + private XpackShareManage proxy() { + return CommonBeanFactory.getBean(this.getClass()); + } + + public XpackShareProxyVO proxyInfo(XpackShareProxyRequest request) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("uuid", request.getUuid()); + XpackShare xpackShare = xpackShareMapper.selectOne(queryWrapper); + if (ObjectUtils.isEmpty(xpackShare)) + return null; + String linkToken = LinkTokenUtil.generate(xpackShare.getCreator(), xpackShare.getResourceId(), xpackShare.getExp(), xpackShare.getPwd(), xpackShare.getOid()); + HttpServletResponse response = ServletUtils.response(); + response.addHeader(AuthConstant.LINK_TOKEN_KEY, linkToken); + Integer type = xpackShare.getType(); + String typeText = (ObjectUtils.isNotEmpty(type) && type == 1) ? "dashboard" : "dataV"; + return new XpackShareProxyVO(xpackShare.getResourceId(), xpackShare.getCreator(), linkExp(xpackShare), pwdValid(xpackShare, request.getCiphertext()), typeText); + } + + private boolean linkExp(XpackShare xpackShare) { + if (ObjectUtils.isEmpty(xpackShare.getExp()) || xpackShare.getExp().equals(0L)) return false; + return System.currentTimeMillis() > xpackShare.getExp(); + } + + private boolean pwdValid(XpackShare xpackShare, String ciphertext) { + if (StringUtils.isBlank(xpackShare.getPwd())) return true; + if (StringUtils.isBlank(ciphertext)) return false; + String text = RsaUtils.decryptStr(ciphertext); + int len = text.length(); + int splitIndex = len - 4; + String pwd = text.substring(splitIndex); + String uuid = text.substring(0, splitIndex); + return StringUtils.equals(xpackShare.getUuid(), uuid) && StringUtils.equals(xpackShare.getPwd(), pwd); + } + + public boolean validatePwd(XpackSharePwdValidator validator) { + String ciphertext = RsaUtils.decryptStr(validator.getCiphertext()); + int len = ciphertext.length(); + int splitIndex = len - 4; + String pwd = ciphertext.substring(splitIndex); + String uuid = ciphertext.substring(0, splitIndex); + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("uuid", uuid); + XpackShare xpackShare = xpackShareMapper.selectOne(queryWrapper); + return StringUtils.equals(xpackShare.getUuid(), uuid) && StringUtils.equals(xpackShare.getPwd(), pwd); + } + + public Map queryRelationByUserId(Long uid) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("creator", uid); + List result = xpackShareMapper.selectList(queryWrapper); + if (CollectionUtils.isNotEmpty(result)) { + return result.stream() + .collect(Collectors.toMap(xpackShare -> String.valueOf(xpackShare.getResourceId()), XpackShare::getUuid)); + } + return new HashMap<>(); + } +} diff --git a/core/core-backend/src/main/java/io/dataease/share/server/XpackShareServer.java b/core/core-backend/src/main/java/io/dataease/share/server/XpackShareServer.java new file mode 100644 index 0000000000..94bb97bb25 --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/share/server/XpackShareServer.java @@ -0,0 +1,76 @@ +package io.dataease.share.server; + +import io.dataease.api.visualization.request.VisualizationWorkbranchQueryRequest; +import io.dataease.api.xpack.share.XpackShareApi; +import io.dataease.api.xpack.share.request.XpackShareExpRequest; +import io.dataease.api.xpack.share.request.XpackShareProxyRequest; +import io.dataease.api.xpack.share.request.XpackSharePwdRequest; +import io.dataease.api.xpack.share.request.XpackSharePwdValidator; +import io.dataease.api.xpack.share.vo.XpackShareGridVO; +import io.dataease.api.xpack.share.vo.XpackShareProxyVO; +import io.dataease.api.xpack.share.vo.XpackShareVO; +import io.dataease.utils.BeanUtils; +import io.dataease.share.dao.auto.entity.XpackShare; +import io.dataease.share.manage.XpackShareManage; +import jakarta.annotation.Resource; +import org.apache.commons.lang3.ObjectUtils; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; +import java.util.Map; + +@RequestMapping("/share") +@RestController +public class XpackShareServer implements XpackShareApi { + + @Resource(name = "xpackShareManage") + private XpackShareManage xpackShareManage; + @Override + public boolean status(Long resourceId) { + return ObjectUtils.isNotEmpty(xpackShareManage.queryByResource(resourceId)); + } + + @Override + public void switcher(Long resourceId) { + xpackShareManage.switcher(resourceId); + } + + @Override + public void editExp(XpackShareExpRequest request) { + xpackShareManage.editExp(request.getResourceId(), request.getExp()); + } + + @Override + public void editPwd(XpackSharePwdRequest request) { + xpackShareManage.editPwd(request.getResourceId(), request.getPwd()); + } + + @Override + public XpackShareVO detail(Long resourceId) { + XpackShare xpackShare = xpackShareManage.queryByResource(resourceId); + if (ObjectUtils.isEmpty(xpackShare)) return null; + return BeanUtils.copyBean(new XpackShareVO(), xpackShare); + } + + @Override + public List query(VisualizationWorkbranchQueryRequest request) { + return xpackShareManage.query(1, 20, request).getRecords(); + } + + @Override + public XpackShareProxyVO proxyInfo(XpackShareProxyRequest request) { + return xpackShareManage.proxyInfo(request); + } + + @Override + public boolean validatePwd(XpackSharePwdValidator validator) { + return xpackShareManage.validatePwd(validator); + } + + @Override + public Map queryRelationByUserId(@PathVariable("uid") Long uid) { + return xpackShareManage.queryRelationByUserId(uid); + } +} diff --git a/core/core-backend/src/main/java/io/dataease/share/util/LinkTokenUtil.java b/core/core-backend/src/main/java/io/dataease/share/util/LinkTokenUtil.java new file mode 100644 index 0000000000..e460e9361e --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/share/util/LinkTokenUtil.java @@ -0,0 +1,23 @@ +package io.dataease.share.util; + +import com.auth0.jwt.JWT; +import com.auth0.jwt.JWTCreator; +import com.auth0.jwt.algorithms.Algorithm; +import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.StringUtils; + +import java.util.Date; + +public class LinkTokenUtil { + private static final String defaultPwd = "link-pwd-fit2cloud"; + public static String generate(Long uid, Long resourceId, Long exp, String pwd, Long oid) { + pwd = StringUtils.isBlank(pwd) ? defaultPwd : pwd; + Algorithm algorithm = Algorithm.HMAC256(pwd); + JWTCreator.Builder builder = JWT.create(); + builder.withClaim("uid", uid).withClaim("resourceId", resourceId).withClaim("oid", oid); + if (ObjectUtils.isNotEmpty(exp) && !exp.equals(0L)) { + builder = builder.withExpiresAt(new Date(exp)); + } + return builder.sign(algorithm); + } +} diff --git a/core/core-backend/src/main/java/io/dataease/system/server/SysParameterServer.java b/core/core-backend/src/main/java/io/dataease/system/server/SysParameterServer.java index eb33745da1..f1a2cd8450 100644 --- a/core/core-backend/src/main/java/io/dataease/system/server/SysParameterServer.java +++ b/core/core-backend/src/main/java/io/dataease/system/server/SysParameterServer.java @@ -3,10 +3,12 @@ package io.dataease.system.server; import io.dataease.api.system.SysParameterApi; import io.dataease.api.system.request.OnlineMapEditor; import io.dataease.api.system.vo.SettingItemVO; +import io.dataease.constant.XpackSettingConstants; import io.dataease.system.dao.auto.entity.CoreSysSetting; import io.dataease.system.manage.SysParameterManage; import jakarta.annotation.Resource; import org.apache.commons.lang3.StringUtils; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -18,6 +20,7 @@ public class SysParameterServer implements SysParameterApi { @Resource private SysParameterManage sysParameterManage; + @Override public String singleVal(String key) { return sysParameterManage.singleVal(key); @@ -45,4 +48,17 @@ public class SysParameterServer implements SysParameterApi { public void saveBasicSetting(List settingItemVOS) { sysParameterManage.saveBasic(settingItemVOS); } + + @Override + public Integer RequestTimeOut() { + Integer frontTimeOut = 60; + List settingItemVOS = queryBasicSetting(); + for (int i = 0; i < settingItemVOS.size(); i++) { + SettingItemVO settingItemVO = settingItemVOS.get(i); + if (StringUtils.isNotBlank(settingItemVO.getPkey()) && settingItemVO.getPkey().equalsIgnoreCase(XpackSettingConstants.Front_Time_Out) && StringUtils.isNotBlank(settingItemVO.getPval())) { + frontTimeOut = Integer.parseInt(settingItemVO.getPval()); + } + } + return frontTimeOut; + } } diff --git a/core/core-backend/src/main/java/io/dataease/template/dao/auto/entity/VisualizationTemplate.java b/core/core-backend/src/main/java/io/dataease/template/dao/auto/entity/VisualizationTemplate.java index d0315f9262..122d0d7989 100644 --- a/core/core-backend/src/main/java/io/dataease/template/dao/auto/entity/VisualizationTemplate.java +++ b/core/core-backend/src/main/java/io/dataease/template/dao/auto/entity/VisualizationTemplate.java @@ -5,11 +5,11 @@ import java.io.Serializable; /** * - * 仪表板模板表 + * * * * @author fit2cloud - * @since 2023-11-06 + * @since 2024-01-16 */ @TableName("visualization_template") public class VisualizationTemplate implements Serializable { @@ -37,7 +37,7 @@ public class VisualizationTemplate implements Serializable { private Integer level; /** - * 模板种类 dataV or dashboard 目录或者文件夹 + * 模版种类 dataV or dashboard 目录或者文件夹 */ private String dvType; @@ -62,7 +62,7 @@ public class VisualizationTemplate implements Serializable { private String snapshot; /** - * 模板类型 system 系统内置 self 用户自建 + * 模版类型 system 系统内置 self 用户自建 */ private String templateType; @@ -81,6 +81,11 @@ public class VisualizationTemplate implements Serializable { */ private String dynamicData; + /** + * 使用次数 + */ + private Integer useCount; + public String getId() { return id; } @@ -185,6 +190,14 @@ public class VisualizationTemplate implements Serializable { this.dynamicData = dynamicData; } + public Integer getUseCount() { + return useCount; + } + + public void setUseCount(Integer useCount) { + this.useCount = useCount; + } + @Override public String toString() { return "VisualizationTemplate{" + @@ -201,6 +214,7 @@ public class VisualizationTemplate implements Serializable { ", templateStyle = " + templateStyle + ", templateData = " + templateData + ", dynamicData = " + dynamicData + + ", useCount = " + useCount + "}"; } } diff --git a/core/core-backend/src/main/java/io/dataease/template/dao/auto/mapper/VisualizationTemplateMapper.java b/core/core-backend/src/main/java/io/dataease/template/dao/auto/mapper/VisualizationTemplateMapper.java index 2a8c72964f..73bfdaff84 100644 --- a/core/core-backend/src/main/java/io/dataease/template/dao/auto/mapper/VisualizationTemplateMapper.java +++ b/core/core-backend/src/main/java/io/dataease/template/dao/auto/mapper/VisualizationTemplateMapper.java @@ -6,11 +6,11 @@ import org.apache.ibatis.annotations.Mapper; /** * - * 仪表板模板表 Mapper 接口 + * Mapper 接口 * * * @author fit2cloud - * @since 2023-11-06 + * @since 2024-01-16 */ @Mapper public interface VisualizationTemplateMapper extends BaseMapper { diff --git a/core/core-backend/src/main/java/io/dataease/template/manage/TemplateCenterManage.java b/core/core-backend/src/main/java/io/dataease/template/manage/TemplateCenterManage.java index 85d631dfca..374e793bb1 100644 --- a/core/core-backend/src/main/java/io/dataease/template/manage/TemplateCenterManage.java +++ b/core/core-backend/src/main/java/io/dataease/template/manage/TemplateCenterManage.java @@ -121,13 +121,17 @@ public class TemplateCenterManage { public MarketBaseResponse searchTemplateRecommend() { + MarketTemplateV2BaseResponse v2BaseResponse = null; + Map templateParams = sysParameterManage.groupVal("template."); + // 模版市场推荐 try { - Map templateParams = sysParameterManage.groupVal("template."); - return baseResponseV2TransRecommend(templateQuery(templateParams), templateParams.get("template.url")); + v2BaseResponse = templateQuery(templateParams); } catch (Exception e) { DEException.throwException(e); } - return null; + // 模版管理使用次数推荐 + List manage = searchTemplateFromManage(); + return baseResponseV2TransRecommend(v2BaseResponse, manage, templateParams.get("template.url")); } public MarketPreviewBaseResponse searchTemplatePreview() { @@ -161,7 +165,7 @@ public class TemplateCenterManage { } } - private MarketBaseResponse baseResponseV2TransRecommend(MarketTemplateV2BaseResponse v2BaseResponse, String url) { + private MarketBaseResponse baseResponseV2TransRecommend(MarketTemplateV2BaseResponse v2BaseResponse,List templateManages, String url) { Map useTime = coreOptRecentManage.findTemplateRecentUseTime(); List categoryVO = getCategoriesV2().stream().filter(node -> !"全部".equalsIgnoreCase(node.getLabel())).collect(Collectors.toList()); Map categoriesMap = categoryVO.stream() @@ -177,6 +181,22 @@ public class TemplateCenterManage { } // 最近使用排序 Collections.sort(contents); + Long countDataV = contents.stream().filter(item -> "PANEL".equals(item.getTemplateType())).count(); + Long countDashboard = contents.stream().filter(item -> "SCREEN".equals(item.getTemplateType())).count(); + List templateDataV = templateManages.stream().filter(item -> "PANEL".equals(item.getTemplateType())).collect(Collectors.toList()); + List templateDashboard = templateManages.stream().filter(item -> "SCREEN".equals(item.getTemplateType())).collect(Collectors.toList()); + if(countDataV<10){ + Long addItemCount = 10 -countDataV; + Long addIndex = templateDataV.size() queryWrapper = new QueryWrapper<>(); queryWrapper.eq("delete_flag", false); - queryWrapper.ne("pid",-1); + queryWrapper.ne("pid", -1); queryWrapper.eq(ObjectUtils.isNotEmpty(request.getLeaf()), "node_type", ObjectUtils.isNotEmpty(request.getLeaf()) && request.getLeaf() ? "leaf" : "folder"); queryWrapper.eq("type", request.getBusiFlag()); queryWrapper.orderByDesc("create_time"); List pos = extMapper.queryNodes(queryWrapper); - if (CollectionUtil.isNotEmpty(pos)) { + if (CollectionUtils.isNotEmpty(pos)) { nodes.addAll(pos.stream().map(this::convert).toList()); } return TreeUtils.mergeTree(nodes, BusiNodeVO.class, false); @@ -81,7 +81,7 @@ public class CoreVisualizationManage { if (isTopNode(tempPid)) continue; delIds.add(tempPid); List childrenIdList = extMapper.queryChildrenId(tempPid); - if (CollectionUtil.isNotEmpty(childrenIdList)) { + if (CollectionUtils.isNotEmpty(childrenIdList)) { childrenIdList.forEach(kid -> { if (!delIds.contains(kid)) { stack.add(kid); @@ -112,7 +112,7 @@ public class CoreVisualizationManage { return preInnerSave(visualizationInfo); } - public Long preInnerSave(DataVisualizationInfo visualizationInfo){ + public Long preInnerSave(DataVisualizationInfo visualizationInfo) { if (visualizationInfo.getId() == null) { Long id = IDUtils.snowID(); visualizationInfo.setId(id); @@ -169,7 +169,7 @@ public class CoreVisualizationManage { } List formatResult(List pos) { - if (CollectionUtil.isEmpty(pos)) { + if (CollectionUtils.isEmpty(pos)) { return new ArrayList<>(); } return pos.stream().map(po -> diff --git a/core/core-backend/src/main/java/io/dataease/visualization/manage/VisualizationStoreManage.java b/core/core-backend/src/main/java/io/dataease/visualization/manage/VisualizationStoreManage.java index 55d55cda18..730939dc3a 100644 --- a/core/core-backend/src/main/java/io/dataease/visualization/manage/VisualizationStoreManage.java +++ b/core/core-backend/src/main/java/io/dataease/visualization/manage/VisualizationStoreManage.java @@ -1,6 +1,5 @@ package io.dataease.visualization.manage; -import cn.hutool.core.collection.CollectionUtil; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; @@ -18,6 +17,7 @@ import io.dataease.visualization.dao.auto.mapper.CoreStoreMapper; import io.dataease.visualization.dao.ext.mapper.CoreStoreExtMapper; import io.dataease.visualization.dao.ext.po.StorePO; import jakarta.annotation.Resource; +import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Component; @@ -84,7 +84,7 @@ public class VisualizationStoreManage { } public List formatResult(List pos) { - if (CollectionUtil.isEmpty(pos)) return new ArrayList<>(); + if (CollectionUtils.isEmpty(pos)) return new ArrayList<>(); return pos.stream().map(po -> new VisualizationStoreVO( po.getStoreId(), po.getResourceId(), po.getName(), diff --git a/core/core-backend/src/main/java/io/dataease/visualization/server/DataVisualizationServer.java b/core/core-backend/src/main/java/io/dataease/visualization/server/DataVisualizationServer.java index 96175826df..4d251d107e 100644 --- a/core/core-backend/src/main/java/io/dataease/visualization/server/DataVisualizationServer.java +++ b/core/core-backend/src/main/java/io/dataease/visualization/server/DataVisualizationServer.java @@ -102,7 +102,7 @@ public class DataVisualizationServer implements DataVisualizationApi { } VisualizationWatermark watermark = watermarkMapper.selectById("system_default"); VisualizationWatermarkVO watermarkVO = new VisualizationWatermarkVO(); - BeanUtils.copyBean(watermarkVO,watermark); + BeanUtils.copyBean(watermarkVO, watermark); result.setWatermarkInfo(watermarkVO); return result; } else { @@ -117,6 +117,11 @@ public class DataVisualizationServer implements DataVisualizationApi { DataVisualizationInfo visualizationInfo = new DataVisualizationInfo(); BeanUtils.copyBean(visualizationInfo, request); visualizationInfo.setNodeType(request.getNodeType() == null ? DataVisualizationConstants.NODE_TYPE.LEAF : request.getNodeType()); + if (request.getSelfWatermarkStatus() != null && request.getSelfWatermarkStatus()) { + visualizationInfo.setSelfWatermarkStatus(1); + } else { + visualizationInfo.setSelfWatermarkStatus(0); + } Long newDvId = coreVisualizationManage.innerSave(visualizationInfo); //保存视图信 chartDataManage.saveChartViewFromVisualization(request.getComponentData(), newDvId, request.getCanvasViewInfo()); @@ -132,12 +137,17 @@ public class DataVisualizationServer implements DataVisualizationApi { } DataVisualizationInfo visualizationInfo = new DataVisualizationInfo(); BeanUtils.copyBean(visualizationInfo, request); - if(DataVisualizationConstants.RESOURCE_OPT_TYPE.COPY.equals(request.getOptType())){ + if (request.getSelfWatermarkStatus() != null && request.getSelfWatermarkStatus()) { + visualizationInfo.setSelfWatermarkStatus(1); + } else { + visualizationInfo.setSelfWatermarkStatus(0); + } + if (DataVisualizationConstants.RESOURCE_OPT_TYPE.COPY.equals(request.getOptType())) { // 复制更新 新建权限插入 visualizationInfoMapper.deleteById(dvId); visualizationInfo.setNodeType(DataVisualizationConstants.NODE_TYPE.LEAF); coreVisualizationManage.innerSave(visualizationInfo); - }else{ + } else { // 检查当前节点的pid是否一致如果不一致 需要调用move 接口(预存 可能会出现pid =-1的情况) if (request.getPid() != -1) { QueryWrapper queryWrapper = new QueryWrapper<>(); @@ -231,7 +241,7 @@ public class DataVisualizationServer implements DataVisualizationApi { extDataVisualizationMapper.copyLinkJumpInfo(copyId); extDataVisualizationMapper.copyLinkJumpTargetInfo(copyId); DataVisualizationInfo visualizationInfoTarget = new DataVisualizationInfo(); - BeanUtils.copyBean(visualizationInfoTarget,newDv); + BeanUtils.copyBean(visualizationInfoTarget, newDv); visualizationInfoTarget.setPid(-1L); coreVisualizationManage.preInnerSave(visualizationInfoTarget); return String.valueOf(newDvId); @@ -261,7 +271,11 @@ public class DataVisualizationServer implements DataVisualizationApi { name = visualizationTemplate.getName(); dvType = visualizationTemplate.getDvType(); // 模板市场记录 - coreOptRecentManage.saveOpt(request.getTemplateId(), OptConstants.OPT_RESOURCE_TYPE.TEMPLATE,OptConstants.OPT_TYPE.NEW); + coreOptRecentManage.saveOpt(request.getTemplateId(), OptConstants.OPT_RESOURCE_TYPE.TEMPLATE, OptConstants.OPT_TYPE.NEW); + VisualizationTemplate visualizationTemplateUpdate = new VisualizationTemplate(); + visualizationTemplateUpdate.setId(visualizationTemplate.getId()); + visualizationTemplateUpdate.setUseCount(visualizationTemplate.getUseCount() == null ? 0 : visualizationTemplate.getUseCount() + 1); + templateMapper.updateById(visualizationTemplateUpdate); } else if (DataVisualizationConstants.NEW_PANEL_FROM.NEW_OUTER_TEMPLATE.equals(newFrom)) { templateStyle = request.getCanvasStyleData(); templateData = request.getComponentData(); @@ -281,7 +295,7 @@ public class DataVisualizationServer implements DataVisualizationApi { name = templateFileInfo.getName(); dvType = templateFileInfo.getDvType(); // 模板市场记录 - coreOptRecentManage.saveOpt(request.getResourceName(), OptConstants.OPT_RESOURCE_TYPE.TEMPLATE,OptConstants.OPT_TYPE.NEW); + coreOptRecentManage.saveOpt(request.getResourceName(), OptConstants.OPT_RESOURCE_TYPE.TEMPLATE, OptConstants.OPT_TYPE.NEW); } // 解析动态数据 Map dynamicDataMap = JsonUtil.parseObject(dynamicData, Map.class); @@ -292,7 +306,7 @@ public class DataVisualizationServer implements DataVisualizationApi { String originViewId = entry.getKey(); String originViewData = JsonUtil.toJSONString(entry.getValue()).toString(); ChartViewDTO chartView = JsonUtil.parseObject(originViewData, ChartViewDTO.class); - if(chartView == null){ + if (chartView == null) { continue; } Long newViewId = IDUtils.snowID(); diff --git a/core/core-backend/src/main/java/io/dataease/visualization/server/StaticResourceServer.java b/core/core-backend/src/main/java/io/dataease/visualization/server/StaticResourceServer.java index 6b07a3ea63..840efa6350 100644 --- a/core/core-backend/src/main/java/io/dataease/visualization/server/StaticResourceServer.java +++ b/core/core-backend/src/main/java/io/dataease/visualization/server/StaticResourceServer.java @@ -1,8 +1,6 @@ package io.dataease.visualization.server; -import cn.hutool.core.codec.Base64Decoder; -import cn.hutool.core.collection.CollectionUtil; import io.dataease.api.visualization.StaticResourceApi; import io.dataease.api.visualization.request.StaticResourceRequest; import io.dataease.exception.DEException; @@ -10,8 +8,10 @@ import io.dataease.utils.FileUtils; import io.dataease.utils.JsonUtil; import io.dataease.utils.LogUtil; import io.dataease.utils.StaticResourceUtils; +import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.util.Assert; +import org.springframework.util.Base64Utils; import org.springframework.util.FileCopyUtils; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -89,17 +89,18 @@ public class StaticResourceServer implements StaticResourceApi { } else { if (StringUtils.isNotEmpty(content)) { Files.createFile(uploadPath); - FileCopyUtils.copy(Base64Decoder.decode(content), Files.newOutputStream(uploadPath)); + FileCopyUtils.copy(Base64Utils.decodeFromString(content), Files.newOutputStream(uploadPath)); } } } catch (Exception e) { LogUtil.error("template static resource save error" + e.getMessage()); } } + @Override public Map findResourceAsBase64(StaticResourceRequest resourceRequest) { Map result = new HashMap<>(); - if (CollectionUtil.isNotEmpty(resourceRequest.getResourcePathList())) { + if (CollectionUtils.isNotEmpty(resourceRequest.getResourcePathList())) { for (String path : resourceRequest.getResourcePathList()) { String value = StaticResourceUtils.getImgFileToBase64(path.substring(path.lastIndexOf("/") + 1, path.length())); result.put(path, value); diff --git a/core/core-backend/src/main/resources/application.yml b/core/core-backend/src/main/resources/application.yml index f838d5d272..87a0091da2 100644 --- a/core/core-backend/src/main/resources/application.yml +++ b/core/core-backend/src/main/resources/application.yml @@ -46,6 +46,7 @@ quartz: dataease: version: '@project.version@' + origin-list: http://192.168.2.70:9080 apisix-api: domain: http://192.168.0.121:9180 key: edd1c9f034335f136f87ad84b625c8f1 diff --git a/core/core-backend/src/main/resources/db/desktop/V2.1__ddl.sql b/core/core-backend/src/main/resources/db/desktop/V2.1__ddl.sql index 5fe6c42145..43b2e5bdf7 100644 --- a/core/core-backend/src/main/resources/db/desktop/V2.1__ddl.sql +++ b/core/core-backend/src/main/resources/db/desktop/V2.1__ddl.sql @@ -1,19 +1,4 @@ DROP TABLE IF EXISTS `visualization_template`; -CREATE TABLE `visualization_template` ( - `id` varchar(50) NOT NULL COMMENT '主键', - `name` varchar(255) DEFAULT NULL COMMENT '名称', - `pid` varchar(255) DEFAULT NULL COMMENT '父级id', - `level` int DEFAULT NULL COMMENT '层级', - `dv_type` varchar(255) DEFAULT NULL COMMENT '模板种类 dataV or dashboard 目录或者文件夹', - `node_type` varchar(255) DEFAULT NULL COMMENT '节点类型 folder or panel 目录或者文件夹', - `create_by` varchar(255) DEFAULT NULL COMMENT '创建人', - `create_time` bigint DEFAULT NULL COMMENT '创建时间', - `snapshot` longtext COMMENT '缩略图', - `template_type` varchar(255) DEFAULT NULL COMMENT '模板类型 system 系统内置 self 用户自建 ', - `template_style` longtext COMMENT 'template 样式', - `template_data` longtext COMMENT 'template 数据', - `dynamic_data` longtext COMMENT '预存数据', - PRIMARY KEY (`id`) CREATE TABLE `visualization_template` ( `id` varchar(50) NOT NULL COMMENT '主键', @@ -85,7 +70,8 @@ VALUES (30, 0, 1, 'toolbox', null, 7, 'icon_template', '/toolbox', 1, 1, 0); INSERT INTO `core_menu` VALUES (31, 30, 2, 'template-setting', 'toolbox/template-setting', 1, 'icon_template', '/template-setting', 0, 1, 1); -ALTER TABLE core_opt_recent ADD `resource_name` varchar(255) NULL COMMENT '资源名称'; +ALTER TABLE core_opt_recent + ADD `resource_name` varchar(255) NULL COMMENT '资源名称'; DROP TABLE IF EXISTS `core_area_custom`; CREATE TABLE `core_area_custom` diff --git a/core/core-backend/src/main/resources/db/desktop/V2.2__update_table_desc_ddl.sql b/core/core-backend/src/main/resources/db/desktop/V2.2__update_table_desc_ddl.sql index 44c70caad0..86ec02bbac 100644 --- a/core/core-backend/src/main/resources/db/desktop/V2.2__update_table_desc_ddl.sql +++ b/core/core-backend/src/main/resources/db/desktop/V2.2__update_table_desc_ddl.sql @@ -1,177 +1,211 @@ -ALTER TABLE `QRTZ_BLOB_TRIGGERS` COMMENT = '自定义触发器存储(开源作业调度框架Quartz)'; -ALTER TABLE `QRTZ_CALENDARS` COMMENT = 'Quartz日历(开源作业调度框架Quartz)'; -ALTER TABLE `QRTZ_CRON_TRIGGERS` COMMENT = 'CronTrigger存储(开源作业调度框架Quartz)'; -ALTER TABLE `QRTZ_FIRED_TRIGGERS` COMMENT = '存储已经触发的trigger相关信息(开源作业调度框架Quartz)'; -ALTER TABLE `QRTZ_JOB_DETAILS` COMMENT = '存储jobDetails信息(开源作业调度框架Quartz)'; -ALTER TABLE `QRTZ_LOCKS` COMMENT = 'Quartz锁表,为多个节点调度提供分布式锁(开源作业调度框架Quartz)'; -ALTER TABLE `QRTZ_PAUSED_TRIGGER_GRPS` COMMENT = '存放暂停掉的触发器(开源作业调度框架Quartz)'; -ALTER TABLE `QRTZ_SCHEDULER_STATE` COMMENT = '存储所有节点的scheduler(开源作业调度框架Quartz)'; -ALTER TABLE `QRTZ_SIMPLE_TRIGGERS` COMMENT = 'SimpleTrigger存储(开源作业调度框架Quartz)'; -ALTER TABLE `QRTZ_SIMPROP_TRIGGERS` COMMENT = '存储CalendarIntervalTrigger和DailyTimeIntervalTrigger两种类型的触发器(开源作业调度框架Quartz)'; -ALTER TABLE `QRTZ_TRIGGERS` COMMENT = '存储定义的trigger(开源作业调度框架Quartz)'; -ALTER TABLE `area` COMMENT = '地图区域表'; -ALTER TABLE `core_area_custom` COMMENT = '自定义地图区域信息表'; -ALTER TABLE `core_chart_view` COMMENT = '组件视图表'; -ALTER TABLE `core_dataset_group` COMMENT = '数据集分组表'; -ALTER TABLE `core_dataset_table` COMMENT = 'table数据集'; -ALTER TABLE `core_dataset_table_field` COMMENT = 'table数据集表字段'; -ALTER TABLE `core_dataset_table_sql_log` COMMENT = 'table数据集查询sql日志'; -ALTER TABLE `core_datasource` COMMENT = '数据源表'; -ALTER TABLE `core_datasource_task` COMMENT = '数据源定时同步任务'; -ALTER TABLE `core_datasource_task_log` COMMENT = '数据源定时同步任务执行日志'; -ALTER TABLE `core_de_engine` COMMENT = '数据引擎'; -ALTER TABLE `core_driver` COMMENT = '驱动'; -ALTER TABLE `core_driver_jar` COMMENT = '驱动详情'; -ALTER TABLE `core_menu` COMMENT = '路由菜单'; -ALTER TABLE `core_opt_recent` COMMENT = '可视化资源表'; -ALTER TABLE `core_rsa` COMMENT = 'rsa 密钥表'; -ALTER TABLE `core_store` COMMENT = '用户收藏表'; -ALTER TABLE `core_sys_setting` COMMENT = '系统设置表'; -ALTER TABLE `data_visualization_info` COMMENT = '可视化大屏信息表'; -ALTER TABLE `de_standalone_version` COMMENT = '数据库版本变更记录表'; -ALTER TABLE `license` COMMENT = '企业版许可证信息表'; -ALTER TABLE `per_api_key` COMMENT = 'API Key 密钥表'; -ALTER TABLE `per_auth_busi_role` COMMENT = '角色资源权限配置'; -ALTER TABLE `per_auth_busi_user` COMMENT = '用户资源权限配置'; -ALTER TABLE `per_auth_menu` COMMENT = '菜单资源权限配置'; -ALTER TABLE `per_busi_resource` COMMENT = '企业资源'; -ALTER TABLE `per_dataset_column_permissions` COMMENT = '数据集列权限'; -ALTER TABLE `per_dataset_row_permissions_tree` COMMENT = '数据集行权限'; -ALTER TABLE `per_embedded_instance` COMMENT = '嵌入式应用'; -ALTER TABLE `per_menu_resource` COMMENT = '菜单资源'; -ALTER TABLE `per_org` COMMENT = '组织机构'; -ALTER TABLE `per_role` COMMENT = '角色'; -ALTER TABLE `per_sys_setting` COMMENT = '系统设置表'; -ALTER TABLE `per_user` COMMENT = '用户表'; -ALTER TABLE `per_user_role` COMMENT = '用户角色表'; -ALTER TABLE `visualization_background` COMMENT = '边框背景表'; -ALTER TABLE `visualization_background_image` COMMENT = '背景图'; -ALTER TABLE `visualization_link_jump` COMMENT = '跳转记录表'; -ALTER TABLE `visualization_link_jump_info` COMMENT = '跳转配置表'; -ALTER TABLE `visualization_link_jump_target_view_info` COMMENT = '跳转目标仪表板视图字段配置表'; -ALTER TABLE `visualization_linkage` COMMENT = '联动记录表'; -ALTER TABLE `visualization_linkage_field` COMMENT = '联动字段'; -ALTER TABLE `visualization_subject` COMMENT = '主题表'; -ALTER TABLE `visualization_template_extend_data` COMMENT = '模板视图明细信息表'; -ALTER TABLE `xpack_setting_authentication` COMMENT = '认证设置'; -ALTER TABLE `xpack_share` COMMENT = '公共链接'; +COMMENT ON TABLE `QRTZ_BLOB_TRIGGERS` + IS '自定义触发器存储(开源作业调度框架Quartz)'; +COMMENT ON TABLE `QRTZ_CALENDARS` + IS 'Quartz日历(开源作业调度框架Quartz)'; +COMMENT ON TABLE `QRTZ_CRON_TRIGGERS` + IS 'CronTrigger存储(开源作业调度框架Quartz)'; +COMMENT ON TABLE `QRTZ_FIRED_TRIGGERS` + IS '存储已经触发的trigger相关信息(开源作业调度框架Quartz)'; +COMMENT ON TABLE `QRTZ_JOB_DETAILS` + IS '存储jobDetails信息(开源作业调度框架Quartz)'; +COMMENT ON TABLE `QRTZ_LOCKS` + IS 'Quartz锁表,为多个节点调度提供分布式锁(开源作业调度框架Quartz)'; +COMMENT ON TABLE `QRTZ_PAUSED_TRIGGER_GRPS` + IS '存放暂停掉的触发器(开源作业调度框架Quartz)'; +COMMENT ON TABLE `QRTZ_SCHEDULER_STATE` + IS '存储所有节点的scheduler(开源作业调度框架Quartz)'; +COMMENT ON TABLE `QRTZ_SIMPLE_TRIGGERS` + IS 'SimpleTrigger存储(开源作业调度框架Quartz)'; +COMMENT ON TABLE `QRTZ_SIMPROP_TRIGGERS` + IS '存储CalendarIntervalTrigger和DailyTimeIntervalTrigger两种类型的触发器(开源作业调度框架Quartz)'; +COMMENT ON TABLE `QRTZ_TRIGGERS` + IS '存储定义的trigger(开源作业调度框架Quartz)'; +COMMENT ON TABLE `area` + IS '地图区域表'; +COMMENT ON TABLE `core_area_custom` + IS '自定义地图区域信息表'; +COMMENT ON TABLE `core_chart_view` + IS '组件视图表'; +COMMENT ON TABLE `core_dataset_group` + IS '数据集分组表'; +COMMENT ON TABLE `core_dataset_table` + IS 'table数据集'; +COMMENT ON TABLE `core_dataset_table_field` + IS 'table数据集表字段'; +COMMENT ON TABLE `core_dataset_table_sql_log` + IS 'table数据集查询sql日志'; +COMMENT ON TABLE `core_datasource` + IS '数据源表'; +COMMENT ON TABLE `core_datasource_task` + IS '数据源定时同步任务'; +COMMENT ON TABLE `core_datasource_task_log` + IS '数据源定时同步任务执行日志'; +COMMENT ON TABLE `core_de_engine` + IS '数据引擎'; +COMMENT ON TABLE `core_driver` + IS '驱动'; +COMMENT ON TABLE `core_driver_jar` + IS '驱动详情'; +COMMENT ON TABLE `core_menu` + IS '路由菜单'; +COMMENT ON TABLE `core_opt_recent` + IS '可视化资源表'; +COMMENT ON TABLE `core_rsa` + IS 'rsa 密钥表'; +COMMENT ON TABLE `core_store` + IS '用户收藏表'; +COMMENT ON TABLE `core_sys_setting` + IS '系统设置表'; +COMMENT ON TABLE `data_visualization_info` + IS '可视化大屏信息表'; + +COMMENT ON TABLE `visualization_background` + IS '边框背景表'; +COMMENT ON TABLE `visualization_background_image` + IS '背景图'; +COMMENT ON TABLE `visualization_link_jump` + IS '跳转记录表'; +COMMENT ON TABLE `visualization_link_jump_info` + IS '跳转配置表'; +COMMENT ON TABLE `visualization_link_jump_target_view_info` + IS '跳转目标仪表板视图字段配置表'; +COMMENT ON TABLE `visualization_linkage` + IS '联动记录表'; +COMMENT ON TABLE `visualization_linkage_field` + IS '联动字段'; +COMMENT ON TABLE `visualization_subject` + IS '主题表'; +COMMENT ON TABLE `visualization_template_extend_data` + IS '模板视图明细信息表'; ALTER TABLE `core_dataset_group` - MODIFY COLUMN `qrtz_instance` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT 'Quartz 实例 ID' AFTER `create_time`; + MODIFY COLUMN `qrtz_instance` varchar(1024) NULL DEFAULT NULL COMMENT 'Quartz 实例 ID'; ALTER TABLE `core_dataset_table_field` - MODIFY COLUMN `size` int(0) NULL DEFAULT NULL COMMENT '字段长度(允许为空,默认0)' AFTER `type`, - MODIFY COLUMN `date_format` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '时间字段类型' AFTER `accuracy`; + MODIFY COLUMN `size` int(0) NULL DEFAULT NULL COMMENT '字段长度(允许为空,默认0)'; +ALTER TABLE `core_dataset_table_field` + MODIFY COLUMN `date_format` varchar(255) NULL DEFAULT NULL COMMENT '时间字段类型'; ALTER TABLE `core_datasource_task` - MODIFY COLUMN `extra_data` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '额外数据' AFTER `last_exec_status`; + MODIFY COLUMN `extra_data` longtext NULL COMMENT '额外数据'; ALTER TABLE `core_datasource_task_log` - MODIFY COLUMN `trigger_type` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '更新频率类型' AFTER `create_time`; + MODIFY COLUMN `trigger_type` varchar(45) NULL DEFAULT NULL COMMENT '更新频率类型'; ALTER TABLE `core_driver_jar` - MODIFY COLUMN `trans_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '替换后的 jar 包名称' AFTER `driver_class`, - MODIFY COLUMN `is_trans_name` tinyint(1) NULL DEFAULT NULL COMMENT '是否将上传 jar 包替换了名称(1-是,0-否)' AFTER `trans_name`; + MODIFY COLUMN `trans_name` varchar(255) NULL DEFAULT NULL COMMENT '替换后的 jar 包名称'; +ALTER TABLE `core_driver_jar` + MODIFY COLUMN `is_trans_name` tinyint(1) NULL DEFAULT NULL COMMENT '是否将上传 jar 包替换了名称(1-是,0-否)'; ALTER TABLE `core_rsa` - MODIFY COLUMN `aes_key` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'AES 加密算法的 key' AFTER `create_time`; + MODIFY COLUMN `aes_key` text NOT NULL COMMENT 'AES 加密算法的 key'; ALTER TABLE `data_visualization_info` - MODIFY COLUMN `id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '主键' FIRST; - -ALTER TABLE `de_standalone_version` - MODIFY COLUMN `installed_rank` int(0) NOT NULL COMMENT '执行顺序(主键)' FIRST, - MODIFY COLUMN `version` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '版本' AFTER `installed_rank`, - MODIFY COLUMN `description` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '描述' AFTER `version`, - MODIFY COLUMN `type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '类型' AFTER `description`, - MODIFY COLUMN `script` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '脚本名称' AFTER `type`, - MODIFY COLUMN `checksum` int(0) NULL DEFAULT NULL COMMENT '脚本内容一致性校验码' AFTER `script`, - MODIFY COLUMN `installed_by` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '执行用户' AFTER `checksum`, - MODIFY COLUMN `installed_on` timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0) COMMENT '执行时间' AFTER `installed_by`, - MODIFY COLUMN `execution_time` int(0) NOT NULL COMMENT '执行时长' AFTER `installed_on`, - MODIFY COLUMN `success` tinyint(1) NOT NULL COMMENT '状态(1-成功,0-失败)' AFTER `execution_time`; - -ALTER TABLE `license` - MODIFY COLUMN `id` bigint(0) NOT NULL COMMENT '主键' FIRST, - MODIFY COLUMN `update_time` bigint(0) NULL DEFAULT NULL COMMENT '更新时间' AFTER `id`, - MODIFY COLUMN `license` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT 'license' AFTER `update_time`, - MODIFY COLUMN `f2c_license` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT 'F2C License' AFTER `license`; - -ALTER TABLE `per_dataset_column_permissions` - MODIFY COLUMN `update_time` bigint(0) NULL DEFAULT NULL COMMENT '更新时间' AFTER `white_list_user`; - -ALTER TABLE `per_dataset_row_permissions_tree` - MODIFY COLUMN `update_time` bigint(0) NULL DEFAULT NULL COMMENT '更新时间' AFTER `white_list_dept`; - -ALTER TABLE `per_user` - MODIFY COLUMN `pwd` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '密码' AFTER `account`; + MODIFY COLUMN `id` varchar(50) NOT NULL COMMENT '主键'; ALTER TABLE `visualization_background` - MODIFY COLUMN `id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '主键' FIRST, - MODIFY COLUMN `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '名称' AFTER `id`, - MODIFY COLUMN `classification` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '分类名' AFTER `name`, - MODIFY COLUMN `content` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '内容' AFTER `classification`, - MODIFY COLUMN `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '备注' AFTER `content`, - MODIFY COLUMN `sort` int(0) NULL DEFAULT NULL COMMENT '排序' AFTER `remark`, - MODIFY COLUMN `upload_time` bigint(0) NULL DEFAULT NULL COMMENT '上传时间' AFTER `sort`, - MODIFY COLUMN `base_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '所在目录地址' AFTER `upload_time`, - MODIFY COLUMN `url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '图片url' AFTER `base_url`; + MODIFY COLUMN `id` varchar(64) NOT NULL COMMENT '主键'; +ALTER TABLE `visualization_background` + MODIFY COLUMN `name` varchar(255) NULL DEFAULT NULL COMMENT '名称'; +ALTER TABLE `visualization_background` + MODIFY COLUMN `classification` varchar(255) NOT NULL COMMENT '分类名'; +ALTER TABLE `visualization_background` + MODIFY COLUMN `content` longtext NULL COMMENT '内容'; +ALTER TABLE `visualization_background` + MODIFY COLUMN `remark` varchar(255) NULL DEFAULT NULL COMMENT '备注'; +ALTER TABLE `visualization_background` + MODIFY COLUMN `sort` int(0) NULL DEFAULT NULL COMMENT '排序'; +ALTER TABLE `visualization_background` + MODIFY COLUMN `upload_time` bigint(0) NULL DEFAULT NULL COMMENT '上传时间'; +ALTER TABLE `visualization_background` + MODIFY COLUMN `base_url` varchar(255) NULL DEFAULT NULL COMMENT '所在目录地址'; +ALTER TABLE `visualization_background` + MODIFY COLUMN `url` varchar(255) NULL DEFAULT NULL COMMENT '图片url'; ALTER TABLE `visualization_background_image` - MODIFY COLUMN `id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '主键' FIRST, - MODIFY COLUMN `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '名称' AFTER `id`, - MODIFY COLUMN `classification` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '分类名' AFTER `name`, - MODIFY COLUMN `content` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '内容' AFTER `classification`, - MODIFY COLUMN `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '备注' AFTER `content`, - MODIFY COLUMN `sort` int(0) NULL DEFAULT NULL COMMENT '排序' AFTER `remark`, - MODIFY COLUMN `upload_time` bigint(0) NULL DEFAULT NULL COMMENT '上传时间' AFTER `sort`, - MODIFY COLUMN `base_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '所在目录地址' AFTER `upload_time`, - MODIFY COLUMN `url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '图片url' AFTER `base_url`; + MODIFY COLUMN `id` varchar(64) NOT NULL COMMENT '主键'; +ALTER TABLE `visualization_background_image` + MODIFY COLUMN `name` varchar(255) NULL DEFAULT NULL COMMENT '名称'; +ALTER TABLE `visualization_background_image` + MODIFY COLUMN `classification` varchar(255) NOT NULL COMMENT '分类名'; +ALTER TABLE `visualization_background_image` + MODIFY COLUMN `content` longtext NULL COMMENT '内容'; +ALTER TABLE `visualization_background_image` + MODIFY COLUMN `remark` varchar(255) NULL DEFAULT NULL COMMENT '备注'; +ALTER TABLE `visualization_background_image` + MODIFY COLUMN `sort` int(0) NULL DEFAULT NULL COMMENT '排序'; +ALTER TABLE `visualization_background_image` + MODIFY COLUMN `upload_time` bigint(0) NULL DEFAULT NULL COMMENT '上传时间'; +ALTER TABLE `visualization_background_image` + MODIFY COLUMN `base_url` varchar(255) NULL DEFAULT NULL COMMENT '所在目录地址'; +ALTER TABLE `visualization_background_image` + MODIFY COLUMN `url` varchar(255) NULL DEFAULT NULL COMMENT '图片url'; ALTER TABLE `visualization_link_jump` - MODIFY COLUMN `id` bigint(0) NOT NULL COMMENT '主键' FIRST, - MODIFY COLUMN `copy_from` bigint(0) NULL DEFAULT NULL COMMENT '复制来源' AFTER `checked`, - MODIFY COLUMN `copy_id` bigint(0) NULL DEFAULT NULL COMMENT '复制来源ID' AFTER `copy_from`; + MODIFY COLUMN `id` bigint(0) NOT NULL COMMENT '主键'; +ALTER TABLE `visualization_link_jump` + MODIFY COLUMN `copy_from` bigint(0) NULL DEFAULT NULL COMMENT '复制来源'; +ALTER TABLE `visualization_link_jump` + MODIFY COLUMN `copy_id` bigint(0) NULL DEFAULT NULL COMMENT '复制来源ID'; ALTER TABLE `visualization_link_jump_info` - MODIFY COLUMN `id` bigint(0) NOT NULL COMMENT '主键' FIRST, - MODIFY COLUMN `copy_from` bigint(0) NULL DEFAULT NULL COMMENT '复制来源' AFTER `attach_params`, - MODIFY COLUMN `copy_id` bigint(0) NULL DEFAULT NULL COMMENT '复制来源ID' AFTER `copy_from`; + MODIFY COLUMN `id` bigint(0) NOT NULL COMMENT '主键'; +ALTER TABLE `visualization_link_jump_info` + MODIFY COLUMN `copy_from` bigint(0) NULL DEFAULT NULL COMMENT '复制来源'; +ALTER TABLE `visualization_link_jump_info` + MODIFY COLUMN `copy_id` bigint(0) NULL DEFAULT NULL COMMENT '复制来源ID'; ALTER TABLE `visualization_link_jump_target_view_info` - MODIFY COLUMN `target_id` bigint(0) NOT NULL COMMENT '主键' FIRST, - MODIFY COLUMN `link_jump_info_id` bigint(0) NULL DEFAULT NULL COMMENT 'visualization_link_jump_info 表的 ID' AFTER `target_id`, - MODIFY COLUMN `target_view_id` bigint(0) NULL DEFAULT NULL COMMENT '目标视图ID' AFTER `source_field_active_id`, - MODIFY COLUMN `target_field_id` bigint(0) NULL DEFAULT NULL COMMENT '目标字段ID' AFTER `target_view_id`, - MODIFY COLUMN `copy_from` bigint(0) NULL DEFAULT NULL COMMENT '复制来源' AFTER `target_field_id`, - MODIFY COLUMN `copy_id` bigint(0) NULL DEFAULT NULL COMMENT '复制来源ID' AFTER `copy_from`; + MODIFY COLUMN `target_id` bigint(0) NOT NULL COMMENT '主键'; +ALTER TABLE `visualization_link_jump_target_view_info` + MODIFY COLUMN `link_jump_info_id` bigint(0) NULL DEFAULT NULL COMMENT 'visualization_link_jump_info 表的 ID'; +ALTER TABLE `visualization_link_jump_target_view_info` + MODIFY COLUMN `target_view_id` bigint(0) NULL DEFAULT NULL COMMENT '目标视图ID'; +ALTER TABLE `visualization_link_jump_target_view_info` + MODIFY COLUMN `target_field_id` bigint(0) NULL DEFAULT NULL COMMENT '目标字段ID'; +ALTER TABLE `visualization_link_jump_target_view_info` + MODIFY COLUMN `copy_from` bigint(0) NULL DEFAULT NULL COMMENT '复制来源'; +ALTER TABLE `visualization_link_jump_target_view_info` + MODIFY COLUMN `copy_id` bigint(0) NULL DEFAULT NULL COMMENT '复制来源ID'; ALTER TABLE `visualization_linkage` - MODIFY COLUMN `id` bigint(0) NOT NULL COMMENT '主键' FIRST, - MODIFY COLUMN `dv_id` bigint(0) NULL DEFAULT NULL COMMENT '联动大屏/仪表板ID' AFTER `id`, - MODIFY COLUMN `ext1` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '扩展字段1' AFTER `linkage_active`, - MODIFY COLUMN `ext2` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '扩展字段2' AFTER `ext1`, - MODIFY COLUMN `copy_from` bigint(0) NULL DEFAULT NULL COMMENT '复制来源' AFTER `ext2`, - MODIFY COLUMN `copy_id` bigint(0) NULL DEFAULT NULL COMMENT '复制来源ID' AFTER `copy_from`; + MODIFY COLUMN `id` bigint(0) NOT NULL COMMENT '主键'; +ALTER TABLE `visualization_linkage` + MODIFY COLUMN `dv_id` bigint(0) NULL DEFAULT NULL COMMENT '联动大屏/仪表板ID'; +ALTER TABLE `visualization_linkage` + MODIFY COLUMN `ext1` varchar(2000) NULL DEFAULT NULL COMMENT '扩展字段1'; +ALTER TABLE `visualization_linkage` + MODIFY COLUMN `ext2` varchar(2000) NULL DEFAULT NULL COMMENT '扩展字段2'; +ALTER TABLE `visualization_linkage` + MODIFY COLUMN `copy_from` bigint(0) NULL DEFAULT NULL COMMENT '复制来源'; +ALTER TABLE `visualization_linkage` + MODIFY COLUMN `copy_id` bigint(0) NULL DEFAULT NULL COMMENT '复制来源ID'; ALTER TABLE `visualization_linkage_field` - MODIFY COLUMN `id` bigint(0) NOT NULL COMMENT '主键' FIRST, - MODIFY COLUMN `copy_from` bigint(0) NULL DEFAULT NULL COMMENT '复制来源' AFTER `update_time`, - MODIFY COLUMN `copy_id` bigint(0) NULL DEFAULT NULL COMMENT '复制来源ID' AFTER `copy_from`; + MODIFY COLUMN `id` bigint(0) NOT NULL COMMENT '主键'; +ALTER TABLE `visualization_linkage_field` + MODIFY COLUMN `copy_from` bigint(0) NULL DEFAULT NULL COMMENT '复制来源'; +ALTER TABLE `visualization_linkage_field` + MODIFY COLUMN `copy_id` bigint(0) NULL DEFAULT NULL COMMENT '复制来源ID'; ALTER TABLE `visualization_subject` - MODIFY COLUMN `create_num` int(0) NOT NULL DEFAULT 0 COMMENT '创建序号' AFTER `cover_url`; + MODIFY COLUMN `create_num` int(0) NOT NULL DEFAULT 0 COMMENT '创建序号'; ALTER TABLE `visualization_template_category` - MODIFY COLUMN `template_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '模版类型 system 系统内置 self 用户自建' AFTER `snapshot`; + MODIFY COLUMN `template_type` varchar(255) NULL DEFAULT NULL COMMENT '模版类型 system 系统内置 self 用户自建'; ALTER TABLE `visualization_template_extend_data` - MODIFY COLUMN `id` bigint(0) NOT NULL COMMENT '主键' FIRST, - MODIFY COLUMN `dv_id` bigint(0) NULL DEFAULT NULL COMMENT '模板ID' AFTER `id`, - MODIFY COLUMN `view_id` bigint(0) NULL DEFAULT NULL COMMENT '视图ID' AFTER `dv_id`, - MODIFY COLUMN `view_details` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '视图详情' AFTER `view_id`, - MODIFY COLUMN `copy_from` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '复制来源' AFTER `view_details`, - MODIFY COLUMN `copy_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '复制来源ID' AFTER `copy_from`; + MODIFY COLUMN `id` bigint(0) NOT NULL COMMENT '主键'; +ALTER TABLE `visualization_template_extend_data` + MODIFY COLUMN `dv_id` bigint(0) NULL DEFAULT NULL COMMENT '模板ID'; +ALTER TABLE `visualization_template_extend_data` + MODIFY COLUMN `view_id` bigint(0) NULL DEFAULT NULL COMMENT '视图ID'; +ALTER TABLE `visualization_template_extend_data` + MODIFY COLUMN `view_details` longtext NULL COMMENT '视图详情'; +ALTER TABLE `visualization_template_extend_data` + MODIFY COLUMN `copy_from` varchar(255) NULL DEFAULT NULL COMMENT '复制来源'; +ALTER TABLE `visualization_template_extend_data` + MODIFY COLUMN `copy_id` varchar(255) NULL DEFAULT NULL COMMENT '复制来源ID'; ALTER TABLE `core_opt_recent` - MODIFY COLUMN `resource_type` int(0) NOT NULL COMMENT '资源类型 1-可视化资源 2-仪表板 3-数据大屏 4-数据集 5-数据源 6-模板' AFTER `uid`; + MODIFY COLUMN `resource_type` int(0) NOT NULL COMMENT '资源类型 1-可视化资源 2-仪表板 3-数据大屏 4-数据集 5-数据源 6-模板'; diff --git a/core/core-backend/src/main/resources/db/desktop/V2.3__ddl.sql b/core/core-backend/src/main/resources/db/desktop/V2.3__ddl.sql index f8a9c19a0e..2ade41ecfc 100644 --- a/core/core-backend/src/main/resources/db/desktop/V2.3__ddl.sql +++ b/core/core-backend/src/main/resources/db/desktop/V2.3__ddl.sql @@ -1,12 +1,25 @@ - DROP TABLE IF EXISTS `visualization_watermark`; -CREATE TABLE `visualization_watermark` ( - `id` varchar(50) NOT NULL COMMENT '主键', - `version` varchar(255) DEFAULT NULL COMMENT '版本号', - `setting_content` longtext COMMENT '设置内容', - `create_by` varchar(255) DEFAULT NULL COMMENT '创建人', - `create_time` bigint(13) DEFAULT NULL COMMENT '创建时间', - PRIMARY KEY (`id`) -) COMMENT='仪表板水印设置表'; +CREATE TABLE `visualization_watermark` +( + `id` varchar(50) NOT NULL COMMENT '主键', + `version` varchar(255) DEFAULT NULL COMMENT '版本号', + `setting_content` longtext COMMENT '设置内容', + `create_by` varchar(255) DEFAULT NULL COMMENT '创建人', + `create_time` bigint(13) DEFAULT NULL COMMENT '创建时间', + PRIMARY KEY (`id`) +) COMMENT ='仪表板水印设置表'; + +INSERT INTO `visualization_watermark` (`id`, `version`, `setting_content`, `create_by`, `create_time`) +VALUES ('system_default', '1.0', + '{\"enable\":false,\"enablePanelCustom\":true,\"type\":\"custom\",\"content\":\"水印\",\"watermark_color\":\"#DD1010\",\"watermark_x_space\":12,\"watermark_y_space\":36,\"watermark_fontsize\":15}', + 'admin', NULL); + + +INSERT INTO `core_sys_setting` (`id`, `pkey`, `pval`, `type`, `sort`) +VALUES (9, 'basic.frontTimeOut', '60', 'text', 1); + +ALTER TABLE `visualization_template` + ADD COLUMN `use_count` int NULL DEFAULT 0 COMMENT '使用次数'; + +update visualization_template set use_count = 0; -INSERT INTO `visualization_watermark` (`id`, `version`, `setting_content`, `create_by`, `create_time`) VALUES ('system_default', '1.0', '{\"enable\":false,\"enablePanelCustom\":true,\"type\":\"custom\",\"content\":\"水印\",\"watermark_color\":\"#DD1010\",\"watermark_x_space\":12,\"watermark_y_space\":36,\"watermark_fontsize\":15}', 'admin', NULL); diff --git a/core/core-backend/src/main/resources/db/migration/V2.2__update_table_desc_ddl.sql b/core/core-backend/src/main/resources/db/migration/V2.2__update_table_desc_ddl.sql index 44c70caad0..36ec14d204 100644 --- a/core/core-backend/src/main/resources/db/migration/V2.2__update_table_desc_ddl.sql +++ b/core/core-backend/src/main/resources/db/migration/V2.2__update_table_desc_ddl.sql @@ -1,132 +1,142 @@ -ALTER TABLE `QRTZ_BLOB_TRIGGERS` COMMENT = '自定义触发器存储(开源作业调度框架Quartz)'; -ALTER TABLE `QRTZ_CALENDARS` COMMENT = 'Quartz日历(开源作业调度框架Quartz)'; -ALTER TABLE `QRTZ_CRON_TRIGGERS` COMMENT = 'CronTrigger存储(开源作业调度框架Quartz)'; -ALTER TABLE `QRTZ_FIRED_TRIGGERS` COMMENT = '存储已经触发的trigger相关信息(开源作业调度框架Quartz)'; -ALTER TABLE `QRTZ_JOB_DETAILS` COMMENT = '存储jobDetails信息(开源作业调度框架Quartz)'; -ALTER TABLE `QRTZ_LOCKS` COMMENT = 'Quartz锁表,为多个节点调度提供分布式锁(开源作业调度框架Quartz)'; -ALTER TABLE `QRTZ_PAUSED_TRIGGER_GRPS` COMMENT = '存放暂停掉的触发器(开源作业调度框架Quartz)'; -ALTER TABLE `QRTZ_SCHEDULER_STATE` COMMENT = '存储所有节点的scheduler(开源作业调度框架Quartz)'; -ALTER TABLE `QRTZ_SIMPLE_TRIGGERS` COMMENT = 'SimpleTrigger存储(开源作业调度框架Quartz)'; -ALTER TABLE `QRTZ_SIMPROP_TRIGGERS` COMMENT = '存储CalendarIntervalTrigger和DailyTimeIntervalTrigger两种类型的触发器(开源作业调度框架Quartz)'; -ALTER TABLE `QRTZ_TRIGGERS` COMMENT = '存储定义的trigger(开源作业调度框架Quartz)'; -ALTER TABLE `area` COMMENT = '地图区域表'; -ALTER TABLE `core_area_custom` COMMENT = '自定义地图区域信息表'; -ALTER TABLE `core_chart_view` COMMENT = '组件视图表'; -ALTER TABLE `core_dataset_group` COMMENT = '数据集分组表'; -ALTER TABLE `core_dataset_table` COMMENT = 'table数据集'; -ALTER TABLE `core_dataset_table_field` COMMENT = 'table数据集表字段'; -ALTER TABLE `core_dataset_table_sql_log` COMMENT = 'table数据集查询sql日志'; -ALTER TABLE `core_datasource` COMMENT = '数据源表'; -ALTER TABLE `core_datasource_task` COMMENT = '数据源定时同步任务'; -ALTER TABLE `core_datasource_task_log` COMMENT = '数据源定时同步任务执行日志'; -ALTER TABLE `core_de_engine` COMMENT = '数据引擎'; -ALTER TABLE `core_driver` COMMENT = '驱动'; -ALTER TABLE `core_driver_jar` COMMENT = '驱动详情'; -ALTER TABLE `core_menu` COMMENT = '路由菜单'; -ALTER TABLE `core_opt_recent` COMMENT = '可视化资源表'; -ALTER TABLE `core_rsa` COMMENT = 'rsa 密钥表'; -ALTER TABLE `core_store` COMMENT = '用户收藏表'; -ALTER TABLE `core_sys_setting` COMMENT = '系统设置表'; -ALTER TABLE `data_visualization_info` COMMENT = '可视化大屏信息表'; -ALTER TABLE `de_standalone_version` COMMENT = '数据库版本变更记录表'; -ALTER TABLE `license` COMMENT = '企业版许可证信息表'; -ALTER TABLE `per_api_key` COMMENT = 'API Key 密钥表'; -ALTER TABLE `per_auth_busi_role` COMMENT = '角色资源权限配置'; -ALTER TABLE `per_auth_busi_user` COMMENT = '用户资源权限配置'; -ALTER TABLE `per_auth_menu` COMMENT = '菜单资源权限配置'; -ALTER TABLE `per_busi_resource` COMMENT = '企业资源'; -ALTER TABLE `per_dataset_column_permissions` COMMENT = '数据集列权限'; -ALTER TABLE `per_dataset_row_permissions_tree` COMMENT = '数据集行权限'; -ALTER TABLE `per_embedded_instance` COMMENT = '嵌入式应用'; -ALTER TABLE `per_menu_resource` COMMENT = '菜单资源'; -ALTER TABLE `per_org` COMMENT = '组织机构'; -ALTER TABLE `per_role` COMMENT = '角色'; -ALTER TABLE `per_sys_setting` COMMENT = '系统设置表'; -ALTER TABLE `per_user` COMMENT = '用户表'; -ALTER TABLE `per_user_role` COMMENT = '用户角色表'; -ALTER TABLE `visualization_background` COMMENT = '边框背景表'; -ALTER TABLE `visualization_background_image` COMMENT = '背景图'; -ALTER TABLE `visualization_link_jump` COMMENT = '跳转记录表'; -ALTER TABLE `visualization_link_jump_info` COMMENT = '跳转配置表'; -ALTER TABLE `visualization_link_jump_target_view_info` COMMENT = '跳转目标仪表板视图字段配置表'; -ALTER TABLE `visualization_linkage` COMMENT = '联动记录表'; -ALTER TABLE `visualization_linkage_field` COMMENT = '联动字段'; -ALTER TABLE `visualization_subject` COMMENT = '主题表'; -ALTER TABLE `visualization_template_extend_data` COMMENT = '模板视图明细信息表'; -ALTER TABLE `xpack_setting_authentication` COMMENT = '认证设置'; -ALTER TABLE `xpack_share` COMMENT = '公共链接'; +ALTER TABLE `QRTZ_BLOB_TRIGGERS` + COMMENT = '自定义触发器存储(开源作业调度框架Quartz)'; +ALTER TABLE `QRTZ_CALENDARS` + COMMENT = 'Quartz日历(开源作业调度框架Quartz)'; +ALTER TABLE `QRTZ_CRON_TRIGGERS` + COMMENT = 'CronTrigger存储(开源作业调度框架Quartz)'; +ALTER TABLE `QRTZ_FIRED_TRIGGERS` + COMMENT = '存储已经触发的trigger相关信息(开源作业调度框架Quartz)'; +ALTER TABLE `QRTZ_JOB_DETAILS` + COMMENT = '存储jobDetails信息(开源作业调度框架Quartz)'; +ALTER TABLE `QRTZ_LOCKS` + COMMENT = 'Quartz锁表,为多个节点调度提供分布式锁(开源作业调度框架Quartz)'; +ALTER TABLE `QRTZ_PAUSED_TRIGGER_GRPS` + COMMENT = '存放暂停掉的触发器(开源作业调度框架Quartz)'; +ALTER TABLE `QRTZ_SCHEDULER_STATE` + COMMENT = '存储所有节点的scheduler(开源作业调度框架Quartz)'; +ALTER TABLE `QRTZ_SIMPLE_TRIGGERS` + COMMENT = 'SimpleTrigger存储(开源作业调度框架Quartz)'; +ALTER TABLE `QRTZ_SIMPROP_TRIGGERS` + COMMENT = '存储CalendarIntervalTrigger和DailyTimeIntervalTrigger两种类型的触发器(开源作业调度框架Quartz)'; +ALTER TABLE `QRTZ_TRIGGERS` + COMMENT = '存储定义的trigger(开源作业调度框架Quartz)'; +ALTER TABLE `area` + COMMENT = '地图区域表'; +ALTER TABLE `core_area_custom` + COMMENT = '自定义地图区域信息表'; +ALTER TABLE `core_chart_view` + COMMENT = '组件视图表'; +ALTER TABLE `core_dataset_group` + COMMENT = '数据集分组表'; +ALTER TABLE `core_dataset_table` + COMMENT = 'table数据集'; +ALTER TABLE `core_dataset_table_field` + COMMENT = 'table数据集表字段'; +ALTER TABLE `core_dataset_table_sql_log` + COMMENT = 'table数据集查询sql日志'; +ALTER TABLE `core_datasource` + COMMENT = '数据源表'; +ALTER TABLE `core_datasource_task` + COMMENT = '数据源定时同步任务'; +ALTER TABLE `core_datasource_task_log` + COMMENT = '数据源定时同步任务执行日志'; +ALTER TABLE `core_de_engine` + COMMENT = '数据引擎'; +ALTER TABLE `core_driver` + COMMENT = '驱动'; +ALTER TABLE `core_driver_jar` + COMMENT = '驱动详情'; +ALTER TABLE `core_menu` + COMMENT = '路由菜单'; +ALTER TABLE `core_opt_recent` + COMMENT = '可视化资源表'; +ALTER TABLE `core_rsa` + COMMENT = 'rsa 密钥表'; +ALTER TABLE `core_store` + COMMENT = '用户收藏表'; +ALTER TABLE `core_sys_setting` + COMMENT = '系统设置表'; +ALTER TABLE `data_visualization_info` + COMMENT = '可视化大屏信息表'; +ALTER TABLE `de_standalone_version` + COMMENT = '数据库版本变更记录表'; + +ALTER TABLE `visualization_background` + COMMENT = '边框背景表'; +ALTER TABLE `visualization_background_image` + COMMENT = '背景图'; +ALTER TABLE `visualization_link_jump` + COMMENT = '跳转记录表'; +ALTER TABLE `visualization_link_jump_info` + COMMENT = '跳转配置表'; +ALTER TABLE `visualization_link_jump_target_view_info` + COMMENT = '跳转目标仪表板视图字段配置表'; +ALTER TABLE `visualization_linkage` + COMMENT = '联动记录表'; +ALTER TABLE `visualization_linkage_field` + COMMENT = '联动字段'; +ALTER TABLE `visualization_subject` + COMMENT = '主题表'; +ALTER TABLE `visualization_template_extend_data` + COMMENT = '模板视图明细信息表'; ALTER TABLE `core_dataset_group` - MODIFY COLUMN `qrtz_instance` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT 'Quartz 实例 ID' AFTER `create_time`; + MODIFY COLUMN `qrtz_instance` varchar(1024) NULL DEFAULT NULL COMMENT 'Quartz 实例 ID' AFTER `create_time`; ALTER TABLE `core_dataset_table_field` MODIFY COLUMN `size` int(0) NULL DEFAULT NULL COMMENT '字段长度(允许为空,默认0)' AFTER `type`, - MODIFY COLUMN `date_format` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '时间字段类型' AFTER `accuracy`; + MODIFY COLUMN `date_format` varchar(255) NULL DEFAULT NULL COMMENT '时间字段类型' AFTER `accuracy`; ALTER TABLE `core_datasource_task` - MODIFY COLUMN `extra_data` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '额外数据' AFTER `last_exec_status`; + MODIFY COLUMN `extra_data` longtext NULL COMMENT '额外数据' AFTER `last_exec_status`; ALTER TABLE `core_datasource_task_log` - MODIFY COLUMN `trigger_type` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '更新频率类型' AFTER `create_time`; + MODIFY COLUMN `trigger_type` varchar(45) NULL DEFAULT NULL COMMENT '更新频率类型' AFTER `create_time`; ALTER TABLE `core_driver_jar` - MODIFY COLUMN `trans_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '替换后的 jar 包名称' AFTER `driver_class`, + MODIFY COLUMN `trans_name` varchar(255) NULL DEFAULT NULL COMMENT '替换后的 jar 包名称' AFTER `driver_class`, MODIFY COLUMN `is_trans_name` tinyint(1) NULL DEFAULT NULL COMMENT '是否将上传 jar 包替换了名称(1-是,0-否)' AFTER `trans_name`; ALTER TABLE `core_rsa` - MODIFY COLUMN `aes_key` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'AES 加密算法的 key' AFTER `create_time`; + MODIFY COLUMN `aes_key` text NOT NULL COMMENT 'AES 加密算法的 key' AFTER `create_time`; ALTER TABLE `data_visualization_info` - MODIFY COLUMN `id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '主键' FIRST; + MODIFY COLUMN `id` varchar(50) NOT NULL COMMENT '主键' FIRST; ALTER TABLE `de_standalone_version` MODIFY COLUMN `installed_rank` int(0) NOT NULL COMMENT '执行顺序(主键)' FIRST, - MODIFY COLUMN `version` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '版本' AFTER `installed_rank`, - MODIFY COLUMN `description` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '描述' AFTER `version`, - MODIFY COLUMN `type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '类型' AFTER `description`, - MODIFY COLUMN `script` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '脚本名称' AFTER `type`, + MODIFY COLUMN `version` varchar(50) NULL DEFAULT NULL COMMENT '版本' AFTER `installed_rank`, + MODIFY COLUMN `description` varchar(200) NOT NULL COMMENT '描述' AFTER `version`, + MODIFY COLUMN `type` varchar(20) NOT NULL COMMENT '类型' AFTER `description`, + MODIFY COLUMN `script` varchar(1000) NOT NULL COMMENT '脚本名称' AFTER `type`, MODIFY COLUMN `checksum` int(0) NULL DEFAULT NULL COMMENT '脚本内容一致性校验码' AFTER `script`, - MODIFY COLUMN `installed_by` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '执行用户' AFTER `checksum`, + MODIFY COLUMN `installed_by` varchar(100) NOT NULL COMMENT '执行用户' AFTER `checksum`, MODIFY COLUMN `installed_on` timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0) COMMENT '执行时间' AFTER `installed_by`, MODIFY COLUMN `execution_time` int(0) NOT NULL COMMENT '执行时长' AFTER `installed_on`, MODIFY COLUMN `success` tinyint(1) NOT NULL COMMENT '状态(1-成功,0-失败)' AFTER `execution_time`; -ALTER TABLE `license` - MODIFY COLUMN `id` bigint(0) NOT NULL COMMENT '主键' FIRST, - MODIFY COLUMN `update_time` bigint(0) NULL DEFAULT NULL COMMENT '更新时间' AFTER `id`, - MODIFY COLUMN `license` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT 'license' AFTER `update_time`, - MODIFY COLUMN `f2c_license` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT 'F2C License' AFTER `license`; - -ALTER TABLE `per_dataset_column_permissions` - MODIFY COLUMN `update_time` bigint(0) NULL DEFAULT NULL COMMENT '更新时间' AFTER `white_list_user`; - -ALTER TABLE `per_dataset_row_permissions_tree` - MODIFY COLUMN `update_time` bigint(0) NULL DEFAULT NULL COMMENT '更新时间' AFTER `white_list_dept`; - -ALTER TABLE `per_user` - MODIFY COLUMN `pwd` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '密码' AFTER `account`; ALTER TABLE `visualization_background` - MODIFY COLUMN `id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '主键' FIRST, - MODIFY COLUMN `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '名称' AFTER `id`, - MODIFY COLUMN `classification` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '分类名' AFTER `name`, - MODIFY COLUMN `content` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '内容' AFTER `classification`, - MODIFY COLUMN `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '备注' AFTER `content`, + MODIFY COLUMN `id` varchar(64) NOT NULL COMMENT '主键' FIRST, + MODIFY COLUMN `name` varchar(255) NULL DEFAULT NULL COMMENT '名称' AFTER `id`, + MODIFY COLUMN `classification` varchar(255) NOT NULL COMMENT '分类名' AFTER `name`, + MODIFY COLUMN `content` longtext NULL COMMENT '内容' AFTER `classification`, + MODIFY COLUMN `remark` varchar(255) NULL DEFAULT NULL COMMENT '备注' AFTER `content`, MODIFY COLUMN `sort` int(0) NULL DEFAULT NULL COMMENT '排序' AFTER `remark`, MODIFY COLUMN `upload_time` bigint(0) NULL DEFAULT NULL COMMENT '上传时间' AFTER `sort`, - MODIFY COLUMN `base_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '所在目录地址' AFTER `upload_time`, - MODIFY COLUMN `url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '图片url' AFTER `base_url`; + MODIFY COLUMN `base_url` varchar(255) NULL DEFAULT NULL COMMENT '所在目录地址' AFTER `upload_time`, + MODIFY COLUMN `url` varchar(255) NULL DEFAULT NULL COMMENT '图片url' AFTER `base_url`; ALTER TABLE `visualization_background_image` - MODIFY COLUMN `id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '主键' FIRST, - MODIFY COLUMN `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '名称' AFTER `id`, - MODIFY COLUMN `classification` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '分类名' AFTER `name`, - MODIFY COLUMN `content` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '内容' AFTER `classification`, - MODIFY COLUMN `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '备注' AFTER `content`, + MODIFY COLUMN `id` varchar(64) NOT NULL COMMENT '主键' FIRST, + MODIFY COLUMN `name` varchar(255) NULL DEFAULT NULL COMMENT '名称' AFTER `id`, + MODIFY COLUMN `classification` varchar(255) NOT NULL COMMENT '分类名' AFTER `name`, + MODIFY COLUMN `content` longtext NULL COMMENT '内容' AFTER `classification`, + MODIFY COLUMN `remark` varchar(255) NULL DEFAULT NULL COMMENT '备注' AFTER `content`, MODIFY COLUMN `sort` int(0) NULL DEFAULT NULL COMMENT '排序' AFTER `remark`, MODIFY COLUMN `upload_time` bigint(0) NULL DEFAULT NULL COMMENT '上传时间' AFTER `sort`, - MODIFY COLUMN `base_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '所在目录地址' AFTER `upload_time`, - MODIFY COLUMN `url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '图片url' AFTER `base_url`; + MODIFY COLUMN `base_url` varchar(255) NULL DEFAULT NULL COMMENT '所在目录地址' AFTER `upload_time`, + MODIFY COLUMN `url` varchar(255) NULL DEFAULT NULL COMMENT '图片url' AFTER `base_url`; ALTER TABLE `visualization_link_jump` MODIFY COLUMN `id` bigint(0) NOT NULL COMMENT '主键' FIRST, @@ -149,8 +159,8 @@ ALTER TABLE `visualization_link_jump_target_view_info` ALTER TABLE `visualization_linkage` MODIFY COLUMN `id` bigint(0) NOT NULL COMMENT '主键' FIRST, MODIFY COLUMN `dv_id` bigint(0) NULL DEFAULT NULL COMMENT '联动大屏/仪表板ID' AFTER `id`, - MODIFY COLUMN `ext1` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '扩展字段1' AFTER `linkage_active`, - MODIFY COLUMN `ext2` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '扩展字段2' AFTER `ext1`, + MODIFY COLUMN `ext1` varchar(2000) NULL DEFAULT NULL COMMENT '扩展字段1' AFTER `linkage_active`, + MODIFY COLUMN `ext2` varchar(2000) NULL DEFAULT NULL COMMENT '扩展字段2' AFTER `ext1`, MODIFY COLUMN `copy_from` bigint(0) NULL DEFAULT NULL COMMENT '复制来源' AFTER `ext2`, MODIFY COLUMN `copy_id` bigint(0) NULL DEFAULT NULL COMMENT '复制来源ID' AFTER `copy_from`; @@ -163,15 +173,15 @@ ALTER TABLE `visualization_subject` MODIFY COLUMN `create_num` int(0) NOT NULL DEFAULT 0 COMMENT '创建序号' AFTER `cover_url`; ALTER TABLE `visualization_template_category` - MODIFY COLUMN `template_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '模版类型 system 系统内置 self 用户自建' AFTER `snapshot`; + MODIFY COLUMN `template_type` varchar(255) NULL DEFAULT NULL COMMENT '模版类型 system 系统内置 self 用户自建' AFTER `snapshot`; ALTER TABLE `visualization_template_extend_data` MODIFY COLUMN `id` bigint(0) NOT NULL COMMENT '主键' FIRST, MODIFY COLUMN `dv_id` bigint(0) NULL DEFAULT NULL COMMENT '模板ID' AFTER `id`, MODIFY COLUMN `view_id` bigint(0) NULL DEFAULT NULL COMMENT '视图ID' AFTER `dv_id`, - MODIFY COLUMN `view_details` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '视图详情' AFTER `view_id`, - MODIFY COLUMN `copy_from` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '复制来源' AFTER `view_details`, - MODIFY COLUMN `copy_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '复制来源ID' AFTER `copy_from`; + MODIFY COLUMN `view_details` longtext NULL COMMENT '视图详情' AFTER `view_id`, + MODIFY COLUMN `copy_from` varchar(255) NULL DEFAULT NULL COMMENT '复制来源' AFTER `view_details`, + MODIFY COLUMN `copy_id` varchar(255) NULL DEFAULT NULL COMMENT '复制来源ID' AFTER `copy_from`; ALTER TABLE `core_opt_recent` MODIFY COLUMN `resource_type` int(0) NOT NULL COMMENT '资源类型 1-可视化资源 2-仪表板 3-数据大屏 4-数据集 5-数据源 6-模板' AFTER `uid`; diff --git a/core/core-backend/src/main/resources/db/migration/V2.3__ddl.sql b/core/core-backend/src/main/resources/db/migration/V2.3__ddl.sql index f8a9c19a0e..e26a77c3ec 100644 --- a/core/core-backend/src/main/resources/db/migration/V2.3__ddl.sql +++ b/core/core-backend/src/main/resources/db/migration/V2.3__ddl.sql @@ -10,3 +10,9 @@ CREATE TABLE `visualization_watermark` ( ) COMMENT='仪表板水印设置表'; INSERT INTO `visualization_watermark` (`id`, `version`, `setting_content`, `create_by`, `create_time`) VALUES ('system_default', '1.0', '{\"enable\":false,\"enablePanelCustom\":true,\"type\":\"custom\",\"content\":\"水印\",\"watermark_color\":\"#DD1010\",\"watermark_x_space\":12,\"watermark_y_space\":36,\"watermark_fontsize\":15}', 'admin', NULL); + +ALTER TABLE `visualization_template` + ADD COLUMN `use_count` int NULL DEFAULT 0 COMMENT '使用次数' AFTER `dynamic_data`; + +update visualization_template set use_count = 0; +INSERT INTO `core_sys_setting` (`id`, `pkey`, `pval`, `type`, `sort`) VALUES (9, 'basic.frontTimeOut', '60', 'text', 1); diff --git a/core/core-backend/src/main/resources/i18n/core_zh_CN.properties b/core/core-backend/src/main/resources/i18n/core_zh_CN.properties index d2f6d4d8c5..926674c050 100644 --- a/core/core-backend/src/main/resources/i18n/core_zh_CN.properties +++ b/core/core-backend/src/main/resources/i18n/core_zh_CN.properties @@ -20,7 +20,7 @@ i18n_menu.org=\u7EC4\u7EC7\u7BA1\u7406 i18n_menu.auth=\u6743\u9650\u914D\u7F6E i18n_menu.sync=\u540C\u6B65\u7BA1\u7406 i18n_menu.summary=\u6982\u89C8 -i18n_menu.ds=\u6570\u636E\u6E90\u7BA1\u7406 +i18n_menu.ds=\u6570\u636e\u8fde\u63a5\u7ba1\u7406 i18n_menu.task=\u4EFB\u52A1\u7BA1\u7406 i18n_menu.embedded=\u5D4C\u5165\u5F0F\u7BA1\u7406 i18n_menu.platform=\u5E73\u53F0\u5BF9\u63A5 diff --git a/core/core-backend/src/main/resources/mybatis/ExtVisualizationTemplateMapper.xml b/core/core-backend/src/main/resources/mybatis/ExtVisualizationTemplateMapper.xml index 7c18f24e46..c4598a13ad 100644 --- a/core/core-backend/src/main/resources/mybatis/ExtVisualizationTemplateMapper.xml +++ b/core/core-backend/src/main/resources/mybatis/ExtVisualizationTemplateMapper.xml @@ -53,12 +53,13 @@ vt.create_time, vt.template_type, vt.SNAPSHOT, + vt.use_count, vtcm.category_id, cor.time as 'recent_use_time' FROM visualization_template vt LEFT JOIN visualization_template_category_map vtcm ON vt.id = vtcm.template_id left JOIN core_opt_recent cor on cor.resource_type = 6 and vt.id = cor.resource_name - ORDER BY vt.create_time DESC + ORDER BY vt.use_count ,vt.create_time DESC diff --git a/core/core-frontend/src/api/about.ts b/core/core-frontend/src/api/about.ts index 1a20032bb7..2b563723ec 100644 --- a/core/core-frontend/src/api/about.ts +++ b/core/core-frontend/src/api/about.ts @@ -3,3 +3,7 @@ import request from '@/config/axios' export const validateApi = data => request.post({ url: '/license/validate', data }) export const buildVersionApi = () => request.get({ url: '/license/version' }) export const updateInfoApi = data => request.post({ url: '/license/update', data }) + +export const checkFreeApi = () => request.get({ url: '/rmonitor/existFree' }) +export const syncFreeApi = () => request.post({ url: '/rmonitor/sync' }) +export const delFreeApi = () => request.post({ url: '/rmonitor/delete' }) diff --git a/core/core-frontend/src/api/datasource.ts b/core/core-frontend/src/api/datasource.ts index 1b32dced92..bc51454740 100644 --- a/core/core-frontend/src/api/datasource.ts +++ b/core/core-frontend/src/api/datasource.ts @@ -111,6 +111,14 @@ export const getDatasetTree = async (data = {}): Promise => { }) } +export const getDsTree = async (data = {}): Promise => { + return request + .post({ url: '/datasource/tree', data: { ...data, ...{ busiFlag: 'datasource' } } }) + .then(res => { + return res?.data + }) +} + export const deleteById = (id: number) => request.get({ url: '/datasource/delete/' + id }) export const getById = (id: number) => request.get({ url: '/datasource/get/' + id }) diff --git a/core/core-frontend/src/api/sync/syncDatasource.ts b/core/core-frontend/src/api/sync/syncDatasource.ts new file mode 100644 index 0000000000..5a9686c8fd --- /dev/null +++ b/core/core-frontend/src/api/sync/syncDatasource.ts @@ -0,0 +1,47 @@ +import request from '@/config/axios' + +export const sourceDsPageApi = (page: number, limit: number, data) => { + return request.post({ url: `/sync/datasource/source/pager/${page}/${limit}`, data }) +} + +export const targetDsPageApi = (page: number, limit: number, data) => { + return request.post({ url: `/sync/datasource/target/pager/${page}/${limit}`, data }) +} +export const latestUseApi = () => { + return request.post({ url: '/sync/datasource/latestUse', data: {} }) +} + +export const validateApi = data => { + return request.post({ url: '/sync/datasource/validate', data }) +} + +export const getSchemaApi = data => { + return request.post({ url: '/sync/datasource/getSchema', data }) +} + +export const saveApi = data => { + return request.post({ url: '/sync/datasource/save', data }) +} + +export const getByIdApi = (id: string) => { + return request.get({ url: `/sync/datasource/get/${id}` }) +} + +export const updateApi = data => { + return request.post({ url: '/sync/datasource/update', data }) +} + +export const deleteByIdApi = (id: string) => { + return request.post({ url: `/sync/datasource/delete/${id}` }) +} + +export const batchDelApi = (ids: string[]) => { + return request.post({ url: `/sync/datasource/batchDel`, data: ids }) +} + +/** + * 获取源数据库字段集合以及目标数据库数据类型集合 + */ +export const getFieldListApi = data => { + return request.post({ url: `/sync/datasource/fields`, data }) +} diff --git a/core/core-frontend/src/api/sync/syncSummary.ts b/core/core-frontend/src/api/sync/syncSummary.ts new file mode 100644 index 0000000000..801c83f963 --- /dev/null +++ b/core/core-frontend/src/api/sync/syncSummary.ts @@ -0,0 +1,26 @@ +import request from '@/config/axios' + +interface IResourceCount { + jobCount: number + datasourceCount: number + jobLogCount: number +} + +export const getResourceCount = () => { + return request + .get({ + url: 'sync/summary/resourceCount', + method: 'get' + }) + .then(res => { + return res.data as IResourceCount + }) +} + +export const getJobLogLienChartInfo = () => { + return request.post({ + url: '/sync/summary/logChartData', + method: 'post', + data: '' + }) +} diff --git a/core/core-frontend/src/api/sync/syncTask.ts b/core/core-frontend/src/api/sync/syncTask.ts new file mode 100644 index 0000000000..f9d7829682 --- /dev/null +++ b/core/core-frontend/src/api/sync/syncTask.ts @@ -0,0 +1,225 @@ +import request from '@/config/axios' + +export interface IGetTaskInfoReq { + id?: string + name?: string +} + +export interface ITaskInfoInsertReq { + [key: string]: any +} + +export interface ISchedulerOption { + interval: number + unit: string +} + +export interface ISource { + type: string + query: string + tables: string + datasourceId: string + tableExtract: string + dsTableList?: IDsTable[] + dsList?: [] + fieldList?: ITableField[] + targetFieldTypeList?: string[] + incrementCheckbox?: string + incrementField?: string +} + +export interface ITableField { + id: string + fieldSource: string + fieldName: string + fieldType: string + remarks: string + fieldSize: number + fieldPrecision: number + fieldPk: boolean + fieldIndex: boolean +} + +export interface ITargetProperty { + /** + * 启用分区on + */ + partitionEnable: string + /** + * 分区类型 + * DateRange 日期 + * NumberRange 数值 + * List 列 + */ + partitionType: string + /** + * 启用动态分区on + */ + dynamicPartitionEnable: string + /** + * 动态分区结束偏移量 + */ + dynamicPartitionEnd: number + /** + * 动态分区间隔单位 + * HOUR WEEK DAY MONTH YEAR + */ + dynamicPartitionTimeUnit: string + /** + * 手动分区列值 + * 多个以','隔开 + */ + manualPartitionColumnValue: string + /** + * 手动分区数值区间开始值 + */ + manualPartitionStart: number + /** + * 手动分区数值区间结束值 + */ + manualPartitionEnd: number + /** + * 手动分区数值区间间隔 + */ + manualPartitionInterval: number + /** + * 手动分区日期区间 + * 2023-09-08 - 2023-09-15 + */ + manualPartitionTimeRange: string + /** + * 手动分区日期区间间隔单位 + */ + manualPartitionTimeUnit: string + /** + * 分区字段 + */ + partitionColumn: string +} + +export interface ITarget { + createTable?: string + type: string + fieldList: ITableField[] + tableName: string + datasourceId: string + targetProperty: string + dsList?: [] + multipleSelection?: ITableField[] + property: ITargetProperty +} + +export class ITaskInfoRes { + id: string + + name: string + + schedulerType: string + + schedulerConf: string + + schedulerOption: ISchedulerOption + + taskKey: string + + desc: string + + executorTimeout: number + + executorFailRetryCount: number + + source: ISource + + target: ITarget + + status: string + startTime: string + stopTime: string + + constructor( + id: string, + name: string, + schedulerType: string, + schedulerConf: string, + taskKey: string, + desc: string, + executorTimeout: number, + executorFailRetryCount: number, + source: ISource, + target: ITarget, + status: string, + startTime: string, + stopTime: string, + schedulerOption: ISchedulerOption + ) { + this.id = id + this.name = name + this.schedulerType = schedulerType + this.schedulerConf = schedulerConf + this.taskKey = taskKey + this.desc = desc + this.executorTimeout = executorTimeout + this.executorFailRetryCount = executorFailRetryCount + this.source = source + this.target = target + this.status = status + this.startTime = startTime + this.stopTime = stopTime + this.schedulerOption = schedulerOption + } +} + +export interface ITaskInfoUpdateReq { + [key: string]: any +} + +export interface IDsTable { + datasourceId: string + name: string + remark: string + enableCheck: string + datasetPath: string +} + +export const getDatasourceListByTypeApi = (type: string) => { + return request.get({ url: `/sync/datasource/list/${type}` }) +} +export const getTaskInfoListApi = (current: number, size: number, data) => { + return request.post({ url: `/sync/task/pager/${current}/${size}`, data: data }) +} + +export const executeOneApi = (id: string) => { + return request.get({ url: `/sync/task/execute/${id}` }) +} + +export const startTaskApi = (id: string) => { + return request.get({ url: `/sync/task/start/${id}` }) +} + +export const stopTaskApi = (id: string) => { + return request.get({ url: `/sync/task/stop/${id}` }) +} + +export const addApi = (data: ITaskInfoInsertReq) => { + return request.post({ url: `/sync/task/add`, data: data }) +} + +export const removeApi = (taskId: string) => { + return request.delete({ url: `/sync/task/remove/${taskId}` }) +} + +export const batchRemoveApi = (taskIds: string[]) => { + return request.post({ url: `/sync/task/batch/del`, data: taskIds }) +} + +export const modifyApi = (data: ITaskInfoUpdateReq) => { + return request.post({ url: `/sync/task/update`, data: data }) +} + +export const findTaskInfoByIdApi = (taskId: string) => { + return request.get({ url: `/sync/task/get/${taskId}` }) +} + +export const getDatasourceTableListApi = (dsId: string) => { + return request.get({ url: `/sync/datasource/table/list/${dsId}` }) +} diff --git a/core/core-frontend/src/api/sync/syncTaskLog.ts b/core/core-frontend/src/api/sync/syncTaskLog.ts new file mode 100644 index 0000000000..d9b6ffc3f6 --- /dev/null +++ b/core/core-frontend/src/api/sync/syncTaskLog.ts @@ -0,0 +1,20 @@ +import request from '@/config/axios' + +export const getTaskLogListApi = (current: number, size: number, data: any) => { + return request.post({ + url: `/sync/task/log/pager/${current}/${size}`, + data: data + }) +} + +export const removeApi = (logId: string) => { + return request.delete({ url: `/sync/task/log/delete/${logId}` }) +} + +export const getTaskLogDetailApi = (logId: string, fromLineNum: number) => { + return request.get({ url: `/sync/task/log/detail/${logId}/${fromLineNum}` }) +} + +export const clear = (clearData: {}) => { + return request.post({ url: `/sync/task/log/clear`, data: clearData }) +} diff --git a/core/core-frontend/src/api/watermark.ts b/core/core-frontend/src/api/watermark.ts index dacfd4c8c3..c5caf45e26 100644 --- a/core/core-frontend/src/api/watermark.ts +++ b/core/core-frontend/src/api/watermark.ts @@ -2,4 +2,4 @@ import request from '@/config/axios' export const watermarkSave = params => request.post({ url: '/watermark/save', data: params }) -export const watermarkFind = () => request.get({ url: 'watermark/find' }) +export const watermarkFind = async () => request.get({ url: 'watermark/find' }) diff --git a/core/core-frontend/src/assets/svg/icon_sync_close_log_details.svg b/core/core-frontend/src/assets/svg/icon_sync_close_log_details.svg new file mode 100644 index 0000000000..7c0dc4cbc5 --- /dev/null +++ b/core/core-frontend/src/assets/svg/icon_sync_close_log_details.svg @@ -0,0 +1,3 @@ + + + diff --git a/core/core-frontend/src/assets/svg/icon_sync_datasource.svg b/core/core-frontend/src/assets/svg/icon_sync_datasource.svg new file mode 100644 index 0000000000..1e3fc9db1d --- /dev/null +++ b/core/core-frontend/src/assets/svg/icon_sync_datasource.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/core/core-frontend/src/assets/svg/icon_sync_log_number.svg b/core/core-frontend/src/assets/svg/icon_sync_log_number.svg new file mode 100644 index 0000000000..49869e0981 --- /dev/null +++ b/core/core-frontend/src/assets/svg/icon_sync_log_number.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/core/core-frontend/src/assets/svg/icon_sync_logs_outlined.svg b/core/core-frontend/src/assets/svg/icon_sync_logs_outlined.svg new file mode 100644 index 0000000000..e310452c05 --- /dev/null +++ b/core/core-frontend/src/assets/svg/icon_sync_logs_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/core/core-frontend/src/assets/svg/icon_sync_target_to_datasource.svg b/core/core-frontend/src/assets/svg/icon_sync_target_to_datasource.svg new file mode 100644 index 0000000000..d84bc12a9e --- /dev/null +++ b/core/core-frontend/src/assets/svg/icon_sync_target_to_datasource.svg @@ -0,0 +1,3 @@ + + + diff --git a/core/core-frontend/src/assets/svg/icon_sync_task_number.svg b/core/core-frontend/src/assets/svg/icon_sync_task_number.svg new file mode 100644 index 0000000000..bce4a1e198 --- /dev/null +++ b/core/core-frontend/src/assets/svg/icon_sync_task_number.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/core/core-frontend/src/components/dashboard/DbCanvasAttr.vue b/core/core-frontend/src/components/dashboard/DbCanvasAttr.vue index 7a338ebfa8..425accb0f3 100644 --- a/core/core-frontend/src/components/dashboard/DbCanvasAttr.vue +++ b/core/core-frontend/src/components/dashboard/DbCanvasAttr.vue @@ -54,16 +54,20 @@ const themeAttrChange = (custom, property, value) => { if (canvasAttrInit) { Object.keys(canvasViewInfo.value).forEach(function (viewId) { const viewInfo = canvasViewInfo.value[viewId] - if (custom === 'customAttr') { - merge(viewInfo['customAttr'], value) - } else { - Object.keys(value).forEach(function (key) { - if (viewInfo[custom][property][key] !== undefined) { - viewInfo[custom][property][key] = value[key] - } - }) + try { + if (custom === 'customAttr') { + merge(viewInfo['customAttr'], value) + } else { + Object.keys(value).forEach(function (key) { + if (viewInfo[custom][property][key] !== undefined) { + viewInfo[custom][property][key] = value[key] + } + }) + } + useEmitt().emitter.emit('renderChart-' + viewId, viewInfo) + } catch (e) { + console.warn('themeAttrChange-error') } - useEmitt().emitter.emit('renderChart-' + viewId, viewInfo) }) snapshotStore.recordSnapshotCache('renderChart') } diff --git a/core/core-frontend/src/components/data-visualization/CanvasAttr.vue b/core/core-frontend/src/components/data-visualization/CanvasAttr.vue index 14a7e741f5..3b12aad8da 100644 --- a/core/core-frontend/src/components/data-visualization/CanvasAttr.vue +++ b/core/core-frontend/src/components/data-visualization/CanvasAttr.vue @@ -33,17 +33,21 @@ const onBaseChange = () => { const themeAttrChange = (custom, property, value) => { if (canvasAttrInit) { Object.keys(canvasViewInfo.value).forEach(function (viewId) { - const viewInfo = canvasViewInfo.value[viewId] - if (custom === 'customAttr') { - merge(viewInfo['customAttr'], value) - } else { - Object.keys(value).forEach(function (key) { - if (viewInfo[custom][property][key] !== undefined) { - viewInfo[custom][property][key] = value[key] - } - }) + try { + const viewInfo = canvasViewInfo.value[viewId] + if (custom === 'customAttr') { + merge(viewInfo['customAttr'], value) + } else { + Object.keys(value).forEach(function (key) { + if (viewInfo[custom][property][key] !== undefined) { + viewInfo[custom][property][key] = value[key] + } + }) + } + useEmitt().emitter.emit('renderChart-' + viewId, viewInfo) + } catch (e) { + console.warn('themeAttrChange-error') } - useEmitt().emitter.emit('renderChart-' + viewId, viewInfo) }) snapshotStore.recordSnapshotCache('renderChart') } @@ -66,7 +70,7 @@ onMounted(() => { effect="dark" size="middle" :min="600" - :max="4096" + :max="50000" v-model="canvasStyleData.width" @change="onBaseChange" controls-position="right" @@ -79,7 +83,7 @@ onMounted(() => { effect="dark" size="middle" :min="600" - :max="4096" + :max="50000" v-model="canvasStyleData.height" @change="onBaseChange" controls-position="right" diff --git a/core/core-frontend/src/components/data-visualization/ComponentToolBar.vue b/core/core-frontend/src/components/data-visualization/ComponentToolBar.vue index 98b13fc8be..c5466c4d22 100644 --- a/core/core-frontend/src/components/data-visualization/ComponentToolBar.vue +++ b/core/core-frontend/src/components/data-visualization/ComponentToolBar.vue @@ -1,7 +1,7 @@ diff --git a/core/core-frontend/src/components/data-visualization/canvas/ContextMenuDetails.vue b/core/core-frontend/src/components/data-visualization/canvas/ContextMenuDetails.vue index e32beddc99..935c23a919 100644 --- a/core/core-frontend/src/components/data-visualization/canvas/ContextMenuDetails.vue +++ b/core/core-frontend/src/components/data-visualization/canvas/ContextMenuDetails.vue @@ -53,8 +53,12 @@ const menuOpt = optName => { } const cut = () => { - const curInfo = getCurInfo() - copyStore.cut(curInfo.componentData) + if (curComponent.value) { + const curInfo = getCurInfo() + copyStore.cut(curInfo.componentData) + } else if (areaData.value.components.length) { + copyStore.cut() + } menuOpt('cut') } @@ -135,6 +139,11 @@ const decompose = () => { menuOpt('decompose') } +const alignment = params => { + composeStore.alignment(params) + snapshotStore.recordSnapshotCache('decompose') +} + // 阻止事件向父级组件传播调用父级的handleMouseDown 导致areaData 被隐藏 const handleComposeMouseDown = e => { e.preventDefault() @@ -147,10 +156,33 @@ const composeDivider = computed(() => { - + 组合 + + 对齐 + + + 左对齐 + 右对齐 + 上对齐 + 下对齐 + 水平居中 + 垂直居中 + + + 复制 粘贴 @@ -190,11 +222,13 @@ const composeDivider = computed(() => { - - diff --git a/core/core-frontend/src/components/drawer-main/src/DrawerMain.vue b/core/core-frontend/src/components/drawer-main/src/DrawerMain.vue index 14b167ef36..13853900ea 100644 --- a/core/core-frontend/src/components/drawer-main/src/DrawerMain.vue +++ b/core/core-frontend/src/components/drawer-main/src/DrawerMain.vue @@ -14,7 +14,8 @@ const props = defineProps({ type: propTypes.string, field: propTypes.string, option: propTypes.array, - title: propTypes.string + title: propTypes.string, + property: propTypes.shape({}) }) ), title: propTypes.string @@ -126,7 +127,8 @@ defineExpose({ :ref="el => (myRefs[index] = el)" v-if="component.type === 'time'" :title="component.title" - @filter-change="v => filterChange(v, component.field, 'eq')" + :property="component.property" + @filter-change="v => filterChange(v, component.field, component.operator)" /> diff --git a/core/core-frontend/src/components/handle-more/src/DvHandleMore.vue b/core/core-frontend/src/components/handle-more/src/DvHandleMore.vue index 2de573b0d7..76930165ea 100644 --- a/core/core-frontend/src/components/handle-more/src/DvHandleMore.vue +++ b/core/core-frontend/src/components/handle-more/src/DvHandleMore.vue @@ -3,7 +3,7 @@ import { Icon } from '@/components/icon-custom' import { propTypes } from '@/utils/propTypes' import type { Placement } from 'element-plus-secondary' import { ref, PropType } from 'vue' -import { XpackComponent } from '@/components/plugin' +import ShareHandler from '@/views/share/share/ShareHandler.vue' export interface Menu { svgName?: string label?: string @@ -44,7 +44,8 @@ const menus = ref([ ]) const handleCommand = (command: string | number | object) => { if (command === 'share') { - shareComponent.value.invokeMethod({ methodName: 'execute' }) + // shareComponent.value.invokeMethod({ methodName: 'execute' }) + shareComponent.value.execute() return } emit('handleCommand', command) @@ -85,9 +86,8 @@ const emit = defineEmits(['handleCommand']) - @@ -21,7 +21,7 @@ diff --git a/core/core-frontend/src/locales/zh-CN.ts b/core/core-frontend/src/locales/zh-CN.ts index 605dfb1fe3..e39fa744a9 100644 --- a/core/core-frontend/src/locales/zh-CN.ts +++ b/core/core-frontend/src/locales/zh-CN.ts @@ -2126,12 +2126,64 @@ export default { setting_basic: { autoCreateUser: '第三方自动创建用户', dsIntervalTime: '数据源检测时间间隔', - dsExecuteTime: '数据源检测频率' + dsExecuteTime: '数据源检测频率', + frontTimeOut: '请求超时时间(秒)' }, template_manage: { name_already_exists_type: '分类名称已存在', the_same_category: '同一分类下,该模板名称已存在' }, + sync_manage: { + title: '同步管理', + ds_search_placeholder: '搜索名称,描述' + }, + sync_datasource: { + title: '数据连接管理', + source_ds: '源数据源', + target_ds: '目标数据源', + add_source_ds: '@:common.add@:sync_datasource.source_ds', + add_target_ds: '@:common.add@:sync_datasource.target_ds', + name: '名称', + desc: '描述', + type: '类型', + status: '状态', + create_time: '创建时间', + update_time: '更新时间', + operation: '操作', + edit: '编辑', + delete: '删除', + confirm_batch_delete_target_ds: '确定删除{0}个目标数据源吗?', + confirm_batch_delete_source_ds: '确定删除{0}个源数据源吗?' + }, + sync_task: { + title: '任务管理', + list: '任务列表', + log_list: '任务日志', + add_task: '添加任务', + name: '名称', + desc: '描述', + status: '状态', + create_time: '创建时间', + update_time: '更新时间', + operation: '操作', + edit: '编辑', + delete: '删除', + start: '启动', + stop: '停止', + trigger_last_time: '上次执行时间', + trigger_next_time: '下次执行时间', + status_success: '成功', + status_running: '执行中', + status_failed: '失败', + status_stopped: '已停止', + status_waiting: '等待执行', + status_done: '执行结束', + status_suspend: '暂停', + running_one: '执行一次', + keep_going: '继续', + log: '日志', + show_log: '查看日志' + }, watermark: { support_params: '当前支持的参数:', enable: '启用水印', diff --git a/core/core-frontend/src/permission.ts b/core/core-frontend/src/permission.ts index 550d8bf2a1..62d0c28fb5 100644 --- a/core/core-frontend/src/permission.ts +++ b/core/core-frontend/src/permission.ts @@ -18,7 +18,7 @@ const { start, done } = useNProgress() const { loadStart, loadDone } = usePageLoading() -const whiteList = ['/login', '/de-link'] // 不重定向白名单 +const whiteList = ['/login', '/de-link', '/chart-view'] // 不重定向白名单 router.beforeEach(async (to, from, next) => { start() diff --git a/core/core-frontend/src/router/index.ts b/core/core-frontend/src/router/index.ts index 41a64f11bf..a6d785a921 100644 --- a/core/core-frontend/src/router/index.ts +++ b/core/core-frontend/src/router/index.ts @@ -112,6 +112,13 @@ export const routes: AppRouteRecordRaw[] = [ meta: { hidden: true } } ] + }, + { + path: '/chart-view', + name: 'chart-view', + hidden: true, + meta: {}, + component: () => import('@/views/chart/ChartView.vue') } ] diff --git a/core/core-frontend/src/store/modules/data-visualization/compose.ts b/core/core-frontend/src/store/modules/data-visualization/compose.ts index f5bca7ae78..78f277edc4 100644 --- a/core/core-frontend/src/store/modules/data-visualization/compose.ts +++ b/core/core-frontend/src/store/modules/data-visualization/compose.ts @@ -56,6 +56,46 @@ export const composeStore = defineStore('compose', { // do updateGroupBorder }, + alignment: function (params) { + const { areaData } = this + if (areaData.components.length === 1) { + // 一个组件不进行组合直接释放 + areaData.components = [] + return + } + if (areaData.components.length > 0 && areaData.style.width === 0) { + // 计算组合区域 + this.calcComposeArea() + } + const { left, top, width, height } = areaData.style + const areaRight = left + width + const areaTransverseCenter = left + width / 2 // 横向中心点 + const areaBottom = top + height + const areaDirectionCenter = top + height / 2 // 纵向中心点 + + areaData.components.forEach(component => { + if (params === 'left') { + // 居左 + component.style.left = left + } else if (params === 'right') { + // 居右 + component.style.left = areaRight - component.style.width + } else if (params === 'top') { + // 居上 + component.style.top = top + } else if (params === 'bottom') { + // 居下 + component.style.top = areaBottom - component.style.height + } else if (params === 'transverse') { + // 横向居中 + component.style.left = areaTransverseCenter - component.style.width / 2 + } else if (params === 'direction') { + // 纵向 + component.style.top = areaDirectionCenter - component.style.height / 2 + } + }) + }, + compose: function (canvasId = 'canvas-main') { const editor = this.editorMap[canvasId] const { areaData } = this diff --git a/core/core-frontend/src/store/modules/data-visualization/copy.ts b/core/core-frontend/src/store/modules/data-visualization/copy.ts index 27d6ab41cc..e61afca528 100644 --- a/core/core-frontend/src/store/modules/data-visualization/copy.ts +++ b/core/core-frontend/src/store/modules/data-visualization/copy.ts @@ -129,6 +129,15 @@ export const copyStore = defineStore('copy', { composeStore.areaData.components.forEach(component => { dvMainStore.deleteComponentById(component.id) }) + composeStore.setAreaData({ + style: { + left: 0, + top: 0, + width: 0, + height: 0 + }, + components: [] + }) } snapshotStore.recordSnapshotCache() this.isCut = true diff --git a/core/core-frontend/src/store/modules/data-visualization/dvMain.ts b/core/core-frontend/src/store/modules/data-visualization/dvMain.ts index dba7db38c1..4c3f21cba4 100644 --- a/core/core-frontend/src/store/modules/data-visualization/dvMain.ts +++ b/core/core-frontend/src/store/modules/data-visualization/dvMain.ts @@ -58,6 +58,7 @@ export const dvMainStore = defineStore('dataVisualization', { pid: null, status: null, selfWatermarkStatus: null, + watermarkInfo: {}, type: null }, // 图表信息 @@ -861,8 +862,8 @@ export const dvMainStore = defineStore('dataVisualization', { pid: null, status: null, selfWatermarkStatus: null, - type: null, - watermarkInfo: null + watermarkInfo: {}, + type: null } }, setViewDataDetails(viewId, dataInfo) { @@ -889,7 +890,7 @@ export const dvMainStore = defineStore('dataVisualization', { } } }, - createInit(dvType, resourceId?, pid?) { + createInit(dvType, resourceId?, pid?, watermarkInfo?) { const optName = dvType === 'dashboard' ? '新建仪表板' : '新建数据大屏' this.dvInfo = { dataState: 'prepare', @@ -899,7 +900,8 @@ export const dvMainStore = defineStore('dataVisualization', { pid: pid, type: dvType, status: 1, - selfWatermarkStatus: 0 + selfWatermarkStatus: true, + watermarkInfo: watermarkInfo } const canvasStyleDataNew = dvType === 'dashboard' @@ -921,6 +923,7 @@ export const dvMainStore = defineStore('dataVisualization', { pid: null, status: null, selfWatermarkStatus: null, + watermarkInfo: {}, type: null } this.canvasStyleData = { ...deepCopy(DEFAULT_CANVAS_STYLE_DATA_DARK), backgroundColor: null } diff --git a/core/core-frontend/src/utils/canvasUtils.ts b/core/core-frontend/src/utils/canvasUtils.ts index 0ea921e542..242edfa343 100644 --- a/core/core-frontend/src/utils/canvasUtils.ts +++ b/core/core-frontend/src/utils/canvasUtils.ts @@ -90,7 +90,7 @@ export function initCanvasDataPrepare(dvId, busiFlag, callBack) { name: canvasInfo.name, pid: canvasInfo.pid, status: canvasInfo.status, - watermarkOpen: canvasInfo.selfWatermarkStatus, + selfWatermarkStatus: canvasInfo.selfWatermarkStatus, type: canvasInfo.type, creatorName: canvasInfo.creatorName, updateName: canvasInfo.updateName, diff --git a/core/core-frontend/src/utils/changeComponentsSizeWithScale.ts b/core/core-frontend/src/utils/changeComponentsSizeWithScale.ts index 2167f9742b..948711a7c2 100644 --- a/core/core-frontend/src/utils/changeComponentsSizeWithScale.ts +++ b/core/core-frontend/src/utils/changeComponentsSizeWithScale.ts @@ -83,6 +83,9 @@ function format(value, scale) { return multiply(value, divide(parseFloat(scale), 100)) } -function getOriginStyle(value, scale) { +function getOriginStyle(value = 0, scale) { + if (!value) { + value = 0 + } return divide(value, divide(parseFloat(scale), 100)) } diff --git a/core/core-frontend/src/views/about/index.vue b/core/core-frontend/src/views/about/index.vue index 9efc818a31..8c2f319fe6 100644 --- a/core/core-frontend/src/views/about/index.vue +++ b/core/core-frontend/src/views/about/index.vue @@ -1,10 +1,17 @@ diff --git a/core/core-frontend/src/views/canvas/DeCanvas.vue b/core/core-frontend/src/views/canvas/DeCanvas.vue index 02b101b8b0..ea0b638099 100644 --- a/core/core-frontend/src/views/canvas/DeCanvas.vue +++ b/core/core-frontend/src/views/canvas/DeCanvas.vue @@ -42,10 +42,11 @@ const domId = ref('de-canvas-' + canvasId.value) const dvMainStore = dvMainStoreWithOut() const snapshotStore = snapshotStoreWithOut() -const { pcMatrixCount, curOriginThemes } = storeToRefs(dvMainStore) +const { pcMatrixCount, curOriginThemes, dvInfo } = storeToRefs(dvMainStore) const canvasOut = ref(null) const canvasInner = ref(null) const canvasInitStatus = ref(false) +const userInfo = ref(null) const state = reactive({ screenWidth: 1920, @@ -59,6 +60,7 @@ const renderState = ref(false) // 仪表板默认 const baseMarginLeft = ref(0) const baseMarginTop = ref(0) const cyGridster = ref(null) +const editDomId = ref('edit-' + canvasId.value) const editStyle = computed(() => { if (canvasStyleData.value && isMainCanvas(canvasId.value)) { @@ -78,6 +80,7 @@ const handleNewFromCanvasMain = newComponentInfo => { syncShapeItemStyle(component, baseWidth.value, baseHeight.value) component.id = guid() component.y = 200 + component.x = cyGridster.value.findPositionX(component) dvMainStore.addComponent({ component: component, index: undefined, @@ -242,7 +245,7 @@ defineExpose({ - + +import ViewWrapper from '@/pages/panel/ViewWrapper.vue' +import { useRoute } from 'vue-router' +import { onBeforeMount } from 'vue' +const route = useRoute() +const init = () => { + const busiFlag = route.query.busiFlag + const dvId = route.query.dvId + const chartId = route.query.chartId + const embeddedToken = route.query.embeddedToken + console.log(busiFlag) + console.log(dvId) + console.log(chartId) + console.log(embeddedToken) + window.DataEaseBi = { + token: embeddedToken, + chartId: chartId, + dvId: dvId, + busiFlag: busiFlag + } +} +onBeforeMount(() => { + init() +}) + + + + + diff --git a/core/core-frontend/src/views/dashboard/index.vue b/core/core-frontend/src/views/dashboard/index.vue index 5006c219e1..c15bd9f280 100644 --- a/core/core-frontend/src/views/dashboard/index.vue +++ b/core/core-frontend/src/views/dashboard/index.vue @@ -17,6 +17,7 @@ import { check, compareStorage } from '@/utils/CrossPermission' import { useCache } from '@/hooks/web/useCache' import { snapshotStoreWithOut } from '@/store/modules/data-visualization/snapshot' import { interactiveStoreWithOut } from '@/store/modules/interactive' +import { watermarkFind } from '@/api/watermark' const interactiveStore = interactiveStoreWithOut() const { wsCache } = useCache() const eventCheck = e => { @@ -93,8 +94,17 @@ onMounted(async () => { }) } else if (opt && opt === 'create') { dataInitState.value = false + let watermarkBaseInfo + try { + await watermarkFind().then(rsp => { + watermarkBaseInfo = rsp.data + watermarkBaseInfo.settingContent = JSON.parse(watermarkBaseInfo.settingContent) + }) + } catch (e) { + console.error('can not find watermark info') + } nextTick(() => { - dvMainStore.createInit('dashboard', null, pid) + dvMainStore.createInit('dashboard', null, pid, watermarkBaseInfo) // 从模板新建 if (createType === 'template') { const deTemplateDataStr = wsCache.get(`de-template-data`) diff --git a/core/core-frontend/src/views/data-visualization/LinkContainer.vue b/core/core-frontend/src/views/data-visualization/LinkContainer.vue index 78a6bef627..a098cca0e3 100644 --- a/core/core-frontend/src/views/data-visualization/LinkContainer.vue +++ b/core/core-frontend/src/views/data-visualization/LinkContainer.vue @@ -1,6 +1,6 @@ - + diff --git a/core/core-frontend/src/views/data-visualization/PreviewHead.vue b/core/core-frontend/src/views/data-visualization/PreviewHead.vue index 72b6868994..0799b18454 100644 --- a/core/core-frontend/src/views/data-visualization/PreviewHead.vue +++ b/core/core-frontend/src/views/data-visualization/PreviewHead.vue @@ -6,7 +6,7 @@ import { useAppStoreWithOut } from '@/store/modules/app' import DvDetailInfo from '@/views/common/DvDetailInfo.vue' import { storeApi, storeStatusApi } from '@/api/visualization/dataVisualization' import { ref, watch, computed } from 'vue' -import { XpackComponent } from '@/components/plugin' +import ShareVisualHead from '@/views/share/share/ShareVisualHead.vue' const dvMainStore = dvMainStoreWithOut() const appStore = useAppStoreWithOut() const { dvInfo } = storeToRefs(dvMainStore) @@ -94,8 +94,7 @@ watch( 预览 - { @@ -221,7 +222,17 @@ onMounted(async () => { }) } else if (opt && opt === 'create') { state.canvasInitStatus = false - dvMainStore.createInit('dataV', null, pid) + let watermarkBaseInfo + try { + await watermarkFind().then(rsp => { + watermarkBaseInfo = rsp.data + watermarkBaseInfo.settingContent = JSON.parse(watermarkBaseInfo.settingContent) + }) + } catch (e) { + console.error('can not find watermark info') + } + + dvMainStore.createInit('dataV', null, pid, watermarkBaseInfo) nextTick(() => { state.canvasInitStatus = true dvMainStore.setDataPrepareState(true) diff --git a/core/core-frontend/src/views/login/index.vue b/core/core-frontend/src/views/login/index.vue index 342c7344a6..a4929ba14d 100644 --- a/core/core-frontend/src/views/login/index.vue +++ b/core/core-frontend/src/views/login/index.vue @@ -173,7 +173,8 @@ const showLoginErrorMsg = () => { onMounted(() => { checkPlatform() if (localStorage.getItem('DE-GATEWAY-FLAG')) { - loginErrorMsg.value = localStorage.getItem('DE-GATEWAY-FLAG') + const msg = localStorage.getItem('DE-GATEWAY-FLAG') + loginErrorMsg.value = decodeURIComponent(msg) showLoginErrorMsg() localStorage.removeItem('DE-GATEWAY-FLAG') logoutHandler(true) diff --git a/core/core-frontend/src/views/share/link/ShareProxy.ts b/core/core-frontend/src/views/share/link/ShareProxy.ts new file mode 100644 index 0000000000..cc7461ee56 --- /dev/null +++ b/core/core-frontend/src/views/share/link/ShareProxy.ts @@ -0,0 +1,42 @@ +import request from '@/config/axios' +import { useCache } from '@/hooks/web/useCache' +const { wsCache } = useCache() +export interface ProxyInfo { + resourceId: string + uid: string + exp?: boolean + pwdValid?: boolean + type: string +} +class ShareProxy { + uuid: string + constructor() { + this.uuid = '' + } + setUuid() { + const curLocation = window.location.href + const uuidObj = curLocation.substring( + curLocation.lastIndexOf('de-link/') + 8, + curLocation.lastIndexOf('?') > 0 ? curLocation.lastIndexOf('?') : curLocation.length + ) + this.uuid = uuidObj + } + async loadProxy() { + this.setUuid() + if (!this.uuid) { + return null + } + const uuid = this.uuid + const url = '/share/proxyInfo' + const param = { uuid, ciphertext: null } + const ciphertext = wsCache.get(`link-${uuid}`) + if (ciphertext) { + param['ciphertext'] = ciphertext + } + const res = await request.post({ url, data: param }) + const proxyInfo: ProxyInfo = res.data as ProxyInfo + return proxyInfo + } +} + +export const shareProxy = new ShareProxy() diff --git a/core/core-frontend/src/views/share/link/error.vue b/core/core-frontend/src/views/share/link/error.vue new file mode 100644 index 0000000000..dad318a8d5 --- /dev/null +++ b/core/core-frontend/src/views/share/link/error.vue @@ -0,0 +1,6 @@ + + + + diff --git a/core/core-frontend/src/views/share/link/exp.vue b/core/core-frontend/src/views/share/link/exp.vue new file mode 100644 index 0000000000..4fbda75f88 --- /dev/null +++ b/core/core-frontend/src/views/share/link/exp.vue @@ -0,0 +1,6 @@ + + + + diff --git a/core/core-frontend/src/views/share/link/index.vue b/core/core-frontend/src/views/share/link/index.vue new file mode 100644 index 0000000000..598474a3b2 --- /dev/null +++ b/core/core-frontend/src/views/share/link/index.vue @@ -0,0 +1,55 @@ + + + + + + + + + + diff --git a/core/core-frontend/src/views/share/link/pwd.vue b/core/core-frontend/src/views/share/link/pwd.vue new file mode 100644 index 0000000000..327c71d8a1 --- /dev/null +++ b/core/core-frontend/src/views/share/link/pwd.vue @@ -0,0 +1,218 @@ + + + + + + + {{ t('pblink.key_pwd') }} + + + + + + + + + + + + + + + {{ msg }} + + + + + {{ + t('pblink.sure_bt') + }} + + + + + + + + + diff --git a/core/core-frontend/src/views/share/share/ShareGrid.vue b/core/core-frontend/src/views/share/share/ShareGrid.vue new file mode 100644 index 0000000000..bb8e449b13 --- /dev/null +++ b/core/core-frontend/src/views/share/share/ShareGrid.vue @@ -0,0 +1,267 @@ + + + + + + + + {{ t(`auth.${activeCommand}`) }} + + + + + + + + + {{ t(`auth.${ele}`) }} + + + + + + + + + + + + + + + + + + + + + + + + + + {{ scope.row.name }} + {{ scope.row.name }} + + + + + + + {{ + formatterTime(null, null, scope.row[item.field]) + }} + {{ scope.row[item.field] }} + + + + + + + + + + + + + + + + + + diff --git a/core/core-frontend/src/views/share/share/ShareHandler.vue b/core/core-frontend/src/views/share/share/ShareHandler.vue new file mode 100644 index 0000000000..0d2892c9dd --- /dev/null +++ b/core/core-frontend/src/views/share/share/ShareHandler.vue @@ -0,0 +1,370 @@ + + + + + + + {{ + t('visualization.share') + }} + + + + + + + {{ shareTips }} + + {{ linkAddr }} + + + + + 必须大于当前时间 + + + + + + + + + + {{ t('commons.reset') }} + + + + + + + + + + + {{ t('visualization.copy_link') }} + + + + + + + + + diff --git a/core/core-frontend/src/views/share/share/SharePanel.vue b/core/core-frontend/src/views/share/share/SharePanel.vue new file mode 100644 index 0000000000..4775ccf04f --- /dev/null +++ b/core/core-frontend/src/views/share/share/SharePanel.vue @@ -0,0 +1,14 @@ + diff --git a/core/core-frontend/src/views/share/share/ShareVisualHead.vue b/core/core-frontend/src/views/share/share/ShareVisualHead.vue new file mode 100644 index 0000000000..5de4706a9c --- /dev/null +++ b/core/core-frontend/src/views/share/share/ShareVisualHead.vue @@ -0,0 +1,332 @@ + + + + + + {{ t('visualization.share') }} + + + + 公共链接分享 + + + {{ shareTips }} + + + + + + + + + 必须大于当前时间 + + + + + + + + + {{ t('commons.reset') }} + + + + + + + + + + {{ t('visualization.copy_link') }} + + + + + + + + + + + diff --git a/core/core-frontend/src/views/share/share/option.ts b/core/core-frontend/src/views/share/share/option.ts new file mode 100644 index 0000000000..f962408183 --- /dev/null +++ b/core/core-frontend/src/views/share/share/option.ts @@ -0,0 +1,35 @@ +export interface ShareInfo { + id: string + exp?: number + uuid: string + pwd?: string +} + +export const SHARE_BASE = '/de-link/' + +export const shortcuts = [ + { + text: '一小时', + value: () => { + const date = new Date() + date.setTime(date.getTime() + 3600 * 1000) + return date + } + }, + { + text: '一天', + value: () => { + const date = new Date() + date.setTime(date.getTime() + 3600 * 1000 * 24) + return date + } + }, + { + text: '一周', + value: () => { + const date = new Date() + date.setTime(date.getTime() + 7 * 3600 * 1000 * 24) + return date + } + } +] diff --git a/core/core-frontend/src/views/system/parameter/basic/BasicEdit.vue b/core/core-frontend/src/views/system/parameter/basic/BasicEdit.vue index 92768c6426..be9875c849 100644 --- a/core/core-frontend/src/views/system/parameter/basic/BasicEdit.vue +++ b/core/core-frontend/src/views/system/parameter/basic/BasicEdit.vue @@ -15,7 +15,8 @@ const options = [ const state = reactive({ form: reactive({ dsIntervalTime: '30', - dsExecuteTime: 'minute' + dsExecuteTime: 'minute', + frontTimeOut: '30' }), settingList: [] }) @@ -165,7 +166,19 @@ defineExpose({ 执行一次 - + + + + diff --git a/core/core-frontend/src/views/system/parameter/basic/BasicInfo.vue b/core/core-frontend/src/views/system/parameter/basic/BasicInfo.vue index 833836a424..91c30d073d 100644 --- a/core/core-frontend/src/views/system/parameter/basic/BasicInfo.vue +++ b/core/core-frontend/src/views/system/parameter/basic/BasicInfo.vue @@ -22,7 +22,7 @@ const editor = ref() const infoTemplate = ref() const tooltips = [ { - key: '请求超时时间', + key: 'setting_basic.frontTimeOut', val: '请求超时时间(单位:秒,注意:保存后刷新浏览器生效)' } ] @@ -45,6 +45,7 @@ const search = cb => { item.pval = item.pval } item.pkey = 'setting_' + item.pkey + console.log(item.pkey) state.templateList.push(item) } cb && cb() diff --git a/core/core-frontend/src/views/template/index.vue b/core/core-frontend/src/views/template/index.vue index 16a5cd7fb1..023668f19a 100644 --- a/core/core-frontend/src/views/template/index.vue +++ b/core/core-frontend/src/views/template/index.vue @@ -468,6 +468,14 @@ const categoryClick = params => { } const saveTemplateEdit = templateEditForm => { + if (templateEditForm.name === '最近使用') { + ElMessage({ + message: '不合法命名,请更换!', + type: 'error', + showClose: true + }) + return + } templateEditFormRef.value.validate(valid => { if (valid) { save({ ...templateEditForm }).then(response => { diff --git a/core/core-frontend/src/views/visualized/data/dataset/index.vue b/core/core-frontend/src/views/visualized/data/dataset/index.vue index 78062dd22e..142fe6429d 100644 --- a/core/core-frontend/src/views/visualized/data/dataset/index.vue +++ b/core/core-frontend/src/views/visualized/data/dataset/index.vue @@ -86,7 +86,7 @@ const resourceCreate = (pid, name) => { pid: pid, type: curCanvasType.value, status: 1, - selfWatermarkStatus: 0 + selfWatermarkStatus: true } const canvasStyleDataNew = curCanvasType.value === 'dashboard' diff --git a/core/core-frontend/src/views/visualized/data/datasource/form/ApiHttpRequestDraw.vue b/core/core-frontend/src/views/visualized/data/datasource/form/ApiHttpRequestDraw.vue index c8b20e0c0c..c0088da9fd 100644 --- a/core/core-frontend/src/views/visualized/data/datasource/form/ApiHttpRequestDraw.vue +++ b/core/core-frontend/src/views/visualized/data/datasource/form/ApiHttpRequestDraw.vue @@ -103,7 +103,7 @@ const rule = reactive({ }, { min: 2, - max: 25, + max: 64, message: t('datasource.input_limit_2_25', [2, 64]), trigger: 'blur' } diff --git a/core/core-frontend/src/views/visualized/data/datasource/form/CreatDsGroup.vue b/core/core-frontend/src/views/visualized/data/datasource/form/CreatDsGroup.vue index 9acd0a2a6a..bce89ddff3 100644 --- a/core/core-frontend/src/views/visualized/data/datasource/form/CreatDsGroup.vue +++ b/core/core-frontend/src/views/visualized/data/datasource/form/CreatDsGroup.vue @@ -272,6 +272,7 @@ const saveDataset = () => { showClose: false, tip: '' } + request.apiConfiguration = '' checkRepeat(request).then(res => { if (res) { ElMessageBox.confirm(t('datasource.has_same_ds'), options as ElMessageBoxOptions).then( diff --git a/core/core-frontend/src/views/visualized/data/datasource/form/EditorDetail.vue b/core/core-frontend/src/views/visualized/data/datasource/form/EditorDetail.vue index e93bd17883..56a5c084f7 100644 --- a/core/core-frontend/src/views/visualized/data/datasource/form/EditorDetail.vue +++ b/core/core-frontend/src/views/visualized/data/datasource/form/EditorDetail.vue @@ -64,7 +64,7 @@ const defaultRule = { }, { min: 2, - max: 25, + max: 64, message: t('datasource.input_limit_2_25', [2, 64]), trigger: 'blur' } diff --git a/core/core-frontend/src/views/visualized/data/datasource/form/index.vue b/core/core-frontend/src/views/visualized/data/datasource/form/index.vue index 1650f7a9c3..9b8fc58a6d 100644 --- a/core/core-frontend/src/views/visualized/data/datasource/form/index.vue +++ b/core/core-frontend/src/views/visualized/data/datasource/form/index.vue @@ -391,6 +391,7 @@ const saveDS = () => { request.configuration = Base64.encode(JSON.stringify(request.configuration)) } const validate = detail.value.submitForm() + request.apiConfiguration = '' validate(val => { if (val) { if (editDs.value && form.id) { @@ -401,7 +402,6 @@ const saveDS = () => { showClose: false, tip: '' } - checkRepeat(request).then(res => { if (res) { ElMessageBox.confirm(t('datasource.has_same_ds'), options as ElMessageBoxOptions).then( diff --git a/core/core-frontend/src/views/watermark/ParamsTips.vue b/core/core-frontend/src/views/watermark/ParamsTips.vue index c77e6c90cd..6734f97071 100644 --- a/core/core-frontend/src/views/watermark/ParamsTips.vue +++ b/core/core-frontend/src/views/watermark/ParamsTips.vue @@ -14,7 +14,9 @@ ${ip}-IP - + @@ -29,5 +31,6 @@ const { t } = useI18n() position: absolute; right: 10px; z-index: 10; + top: 5px; } diff --git a/core/core-frontend/src/views/watermark/index.vue b/core/core-frontend/src/views/watermark/index.vue index 0d023a5b47..b2f69fb9c0 100644 --- a/core/core-frontend/src/views/watermark/index.vue +++ b/core/core-frontend/src/views/watermark/index.vue @@ -113,6 +113,7 @@ import { ElMessage } from 'element-plus-secondary/es' import { personInfoApi } from '@/api/user' import { getNow, watermark } from '@/components/watermark/watermark' import { useI18n } from '@/hooks/web/useI18n' +import ParamsTips from '@/views/watermark/ParamsTips.vue' const { t } = useI18n() const state = reactive({ diff --git a/core/core-frontend/src/views/workbranch/ShortcutTable.vue b/core/core-frontend/src/views/workbranch/ShortcutTable.vue index 5cbc01c038..16fbb211c3 100644 --- a/core/core-frontend/src/views/workbranch/ShortcutTable.vue +++ b/core/core-frontend/src/views/workbranch/ShortcutTable.vue @@ -6,11 +6,13 @@ import GridTable from '@/components/grid-table/src/GridTable.vue' import { useRouter } from 'vue-router' import dayjs from 'dayjs' import { shortcutOption } from './ShortcutOption' -import { XpackComponent } from '@/components/plugin' +/* import { XpackComponent } from '@/components/plugin' */ import { interactiveStoreWithOut } from '@/store/modules/interactive' import { storeApi } from '@/api/visualization/dataVisualization' import { useCache } from '@/hooks/web/useCache' import { useUserStoreWithOut } from '@/store/modules/user' +import ShareGrid from '@/views/share/share/ShareGrid.vue' +import ShareHandler from '@/views/share/share/ShareHandler.vue' const userStore = useUserStoreWithOut() const { resolve } = useRouter() const { t } = useI18n() @@ -111,17 +113,18 @@ const loadTableData = () => { }) } -const panelLoad = paneInfo => { +/* const panelLoad = paneInfo => { tablePaneList.value.push({ title: paneInfo.title, name: paneInfo.name, disabled: tablePaneList.value[1].disabled }) -} +} */ const tablePaneList = ref([ { title: '最近使用', name: 'recent', disabled: false }, - { title: '我的收藏', name: 'store', disabled: false } + { title: '我的收藏', name: 'store', disabled: false }, + { title: t('visualization.share_out'), name: 'share', disabled: false } ]) const busiAuthList = getBusiListWithPermission() @@ -206,8 +209,9 @@ const getEmptyDesc = (): string => { - - + + + { - - + diff --git a/de-xpack b/de-xpack index d17d3775de..e71e615287 160000 --- a/de-xpack +++ b/de-xpack @@ -1 +1 @@ -Subproject commit d17d3775defcb7bbe2603121a417982a0811af4f +Subproject commit e71e6152874ed49933d3befeee6ea2c9310a94f4 diff --git a/installer/dataease/docker-compose-task.yml b/installer/dataease/docker-compose-task.yml new file mode 100644 index 0000000000..b16ce50b4a --- /dev/null +++ b/installer/dataease/docker-compose-task.yml @@ -0,0 +1,11 @@ +version: '2.1' +services: + task-actuator: + image: registry.cn-qingdao.aliyuncs.com/dataease/dataease-sync-task:DE_TAG + container_name: sync-task-actuator + ports: + - 9001:9001 + volumes: + - ${DE_BASE}/dataease2.0/logs:/opt/dataease2.0/logs + networks: + - dataease-network \ No newline at end of file diff --git a/installer/dataease/templates/application.yml b/installer/dataease/templates/application.yml index a9e6a81f78..27b355fd86 100644 --- a/installer/dataease/templates/application.yml +++ b/installer/dataease/templates/application.yml @@ -13,4 +13,9 @@ spring: dataease: apisix-api: domain: http://apisix:9180 - key: DE_APISIX_KEY \ No newline at end of file + key: DE_APISIX_KEY +task: + executor: + address: http://sync-task-actuator:9001 + log: + path: /opt/dataease2.0/logs/sync-task/task-handler-log \ No newline at end of file diff --git a/installer/dectl b/installer/dectl index 3ad4b7d1f5..5749d3160d 100644 --- a/installer/dectl +++ b/installer/dectl @@ -52,6 +52,14 @@ function _check_apisix_init() { _prepare_apisix fi } +function _check_task_init() { + if [[ $DE_INSTALL_MODE != "community" ]];then + _prepare_task + fi +} +function _prepare_task() { + compose_files="${compose_files} -f docker-compose-task.yml" +} function _prepare_apisix() { if [[ -z $DE_APISIX_KEY ]];then need_init_apisix=true @@ -132,6 +140,7 @@ function status() { function start() { echo _check_apisix_init + _check_task_init cd ${DE_RUNNING_BASE} ${compose_cmd} ${compose_files} up -d _healthcheck diff --git a/installer/install.sh b/installer/install.sh index dfe7403778..883691c886 100644 --- a/installer/install.sh +++ b/installer/install.sh @@ -63,7 +63,8 @@ env | grep DE_ >.env mkdir -p ${DE_RUN_BASE}/{cache,logs,conf} mkdir -p ${DE_RUN_BASE}/data/{mysql,static-resource,map,etcd_data,geo} mkdir -p ${DE_RUN_BASE}/apisix/logs -chmod 777 ${DE_RUN_BASE}/apisix/logs ${DE_RUN_BASE}/data/etcd_data +mkdir -p ${DE_RUN_BASE}/task/logs +chmod 777 ${DE_RUN_BASE}/apisix/logs ${DE_RUN_BASE}/data/etcd_data ${DE_RUN_BASE}/task/logs if [ "${DE_EXTERNAL_MYSQL}" = "false" ]; then compose_files="${compose_files} -f docker-compose-mysql.yml" diff --git a/pom.xml b/pom.xml index 017a46cfd1..60fa8cd8ca 100644 --- a/pom.xml +++ b/pom.xml @@ -16,22 +16,21 @@ 2.3.0 17 UTF-8 - 2022.0.0.0-RC1 + 2022.0.0.0 2022.0.0 - 3.0.0 + 3.0.2 3.9.0 17 17 3.5.3.1 2.2.220 4.4.0 - 1.35.1 + 1.35.2 2.6.0 3.5.2 3.12.1 2.3 3.1.0 - 5.8.24 3.10.8 1.74 4.13.2 @@ -116,16 +115,6 @@ org.projectlombok lombok - - cn.hutool - hutool-core - ${hutool.version} - - - cn.hutool - hutool-crypto - ${hutool.version} - org.bouncycastle diff --git a/sdk/api/api-base/src/main/java/io/dataease/api/rmonitor/ResourceMonitorApi.java b/sdk/api/api-base/src/main/java/io/dataease/api/rmonitor/ResourceMonitorApi.java new file mode 100644 index 0000000000..0a318de9a5 --- /dev/null +++ b/sdk/api/api-base/src/main/java/io/dataease/api/rmonitor/ResourceMonitorApi.java @@ -0,0 +1,16 @@ +package io.dataease.api.rmonitor; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; + +public interface ResourceMonitorApi { + + @GetMapping("/existFree") + boolean existFree(); + + @PostMapping("/delete") + void delete(); + + @PostMapping("/sync") + void sync(); +} diff --git a/sdk/api/api-base/src/main/java/io/dataease/api/system/SysParameterApi.java b/sdk/api/api-base/src/main/java/io/dataease/api/system/SysParameterApi.java index 4691253cea..528278ffa0 100644 --- a/sdk/api/api-base/src/main/java/io/dataease/api/system/SysParameterApi.java +++ b/sdk/api/api-base/src/main/java/io/dataease/api/system/SysParameterApi.java @@ -39,4 +39,8 @@ public interface SysParameterApi { @PostMapping("/basic/save") void saveBasicSetting(@RequestBody List settingItemVOS); + @Operation(summary = "查询超时时间(非xpack)") + @GetMapping("/requestTimeOut") + public Integer RequestTimeOut(); + } diff --git a/sdk/api/api-base/src/main/java/io/dataease/api/template/vo/VisualizationTemplateVO.java b/sdk/api/api-base/src/main/java/io/dataease/api/template/vo/VisualizationTemplateVO.java index 3f3a5cc1c6..f560f3f9f0 100644 --- a/sdk/api/api-base/src/main/java/io/dataease/api/template/vo/VisualizationTemplateVO.java +++ b/sdk/api/api-base/src/main/java/io/dataease/api/template/vo/VisualizationTemplateVO.java @@ -76,6 +76,11 @@ public class VisualizationTemplateVO { */ private String dynamicData; + /** + * 使用次数 + */ + private Integer useCount; + /** * 分类 */ diff --git a/sdk/api/api-base/src/main/java/io/dataease/api/visualization/vo/DataVisualizationVO.java b/sdk/api/api-base/src/main/java/io/dataease/api/visualization/vo/DataVisualizationVO.java index c13f28eb05..67c596c04c 100644 --- a/sdk/api/api-base/src/main/java/io/dataease/api/visualization/vo/DataVisualizationVO.java +++ b/sdk/api/api-base/src/main/java/io/dataease/api/visualization/vo/DataVisualizationVO.java @@ -74,7 +74,7 @@ public class DataVisualizationVO implements Serializable { /** * 是否单独打开水印 0-关闭 1-开启 */ - private Integer selfWatermarkStatus; + private Boolean selfWatermarkStatus; /** * 排序 diff --git a/sdk/api/api-permissions/src/main/java/io/dataease/api/permissions/auth/api/InteractiveAuthApi.java b/sdk/api/api-permissions/src/main/java/io/dataease/api/permissions/auth/api/InteractiveAuthApi.java index 396be3149e..f8014a71fe 100644 --- a/sdk/api/api-permissions/src/main/java/io/dataease/api/permissions/auth/api/InteractiveAuthApi.java +++ b/sdk/api/api-permissions/src/main/java/io/dataease/api/permissions/auth/api/InteractiveAuthApi.java @@ -75,4 +75,6 @@ public interface InteractiveAuthApi { @GetMapping("/query2Root/{id}/{flag}") List query2Root(@PathVariable("id") Long id, @PathVariable("flag") Integer flag); + @GetMapping("/checkEmpty") + boolean checkEmpty(); } diff --git a/sdk/api/api-permissions/src/main/java/io/dataease/api/permissions/auth/dto/BusiPerEditor.java b/sdk/api/api-permissions/src/main/java/io/dataease/api/permissions/auth/dto/BusiPerEditor.java index e6d7f8e681..b2fba32d5c 100644 --- a/sdk/api/api-permissions/src/main/java/io/dataease/api/permissions/auth/dto/BusiPerEditor.java +++ b/sdk/api/api-permissions/src/main/java/io/dataease/api/permissions/auth/dto/BusiPerEditor.java @@ -3,10 +3,12 @@ package io.dataease.api.permissions.auth.dto; import io.dataease.api.permissions.auth.vo.PermissionItem; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; +import lombok.EqualsAndHashCode; import java.io.Serial; import java.io.Serializable; import java.util.List; +@EqualsAndHashCode(callSuper = true) @Schema(description = "业务权限编辑器") @Data public class BusiPerEditor extends BusiPermissionRequest implements Serializable { diff --git a/sdk/api/api-permissions/src/main/java/io/dataease/api/permissions/auth/dto/BusiTargetPerCreator.java b/sdk/api/api-permissions/src/main/java/io/dataease/api/permissions/auth/dto/BusiTargetPerCreator.java index 9a0d30e0ea..ffe61ec87f 100644 --- a/sdk/api/api-permissions/src/main/java/io/dataease/api/permissions/auth/dto/BusiTargetPerCreator.java +++ b/sdk/api/api-permissions/src/main/java/io/dataease/api/permissions/auth/dto/BusiTargetPerCreator.java @@ -2,6 +2,9 @@ package io.dataease.api.permissions.auth.dto; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) @Schema(description = "资源权限构造器") @Data public class BusiTargetPerCreator extends MenuTargetPerCreator{ diff --git a/sdk/api/api-permissions/src/main/java/io/dataease/api/permissions/auth/dto/MenuPerEditor.java b/sdk/api/api-permissions/src/main/java/io/dataease/api/permissions/auth/dto/MenuPerEditor.java index b228cb5805..2de268c7fc 100644 --- a/sdk/api/api-permissions/src/main/java/io/dataease/api/permissions/auth/dto/MenuPerEditor.java +++ b/sdk/api/api-permissions/src/main/java/io/dataease/api/permissions/auth/dto/MenuPerEditor.java @@ -3,11 +3,13 @@ package io.dataease.api.permissions.auth.dto; import io.dataease.api.permissions.auth.vo.PermissionItem; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; +import lombok.EqualsAndHashCode; import java.io.Serial; import java.io.Serializable; import java.util.List; +@EqualsAndHashCode(callSuper = true) @Schema(description = "菜单权限编辑器") @Data public class MenuPerEditor extends MenuPermissionRequest implements Serializable { diff --git a/sdk/api/api-permissions/src/main/java/io/dataease/api/permissions/auth/dto/MenuTargetPerCreator.java b/sdk/api/api-permissions/src/main/java/io/dataease/api/permissions/auth/dto/MenuTargetPerCreator.java index f3b5d3aa24..9389ec11c8 100644 --- a/sdk/api/api-permissions/src/main/java/io/dataease/api/permissions/auth/dto/MenuTargetPerCreator.java +++ b/sdk/api/api-permissions/src/main/java/io/dataease/api/permissions/auth/dto/MenuTargetPerCreator.java @@ -3,8 +3,10 @@ package io.dataease.api.permissions.auth.dto; import io.dataease.api.permissions.auth.vo.PermissionItem; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; +import lombok.EqualsAndHashCode; import java.util.List; +@EqualsAndHashCode(callSuper = true) @Schema(description = "菜单权限构造器") @Data public class MenuTargetPerCreator extends TargetPerCreator{ diff --git a/sdk/api/api-permissions/src/main/java/io/dataease/api/permissions/auth/dto/PermissionBO.java b/sdk/api/api-permissions/src/main/java/io/dataease/api/permissions/auth/dto/PermissionBO.java index 7a99449bde..03f4968cc1 100644 --- a/sdk/api/api-permissions/src/main/java/io/dataease/api/permissions/auth/dto/PermissionBO.java +++ b/sdk/api/api-permissions/src/main/java/io/dataease/api/permissions/auth/dto/PermissionBO.java @@ -2,8 +2,10 @@ package io.dataease.api.permissions.auth.dto; import io.dataease.api.permissions.auth.vo.PermissionItem; import lombok.Data; +import lombok.EqualsAndHashCode; +@EqualsAndHashCode(callSuper = true) @Data public class PermissionBO extends PermissionItem { diff --git a/sdk/api/api-permissions/src/main/java/io/dataease/api/permissions/dataset/dto/DatasetRowPermissionsTreeRequest.java b/sdk/api/api-permissions/src/main/java/io/dataease/api/permissions/dataset/dto/DatasetRowPermissionsTreeRequest.java index 2f6ff53749..942be9b826 100644 --- a/sdk/api/api-permissions/src/main/java/io/dataease/api/permissions/dataset/dto/DatasetRowPermissionsTreeRequest.java +++ b/sdk/api/api-permissions/src/main/java/io/dataease/api/permissions/dataset/dto/DatasetRowPermissionsTreeRequest.java @@ -1,11 +1,13 @@ package io.dataease.api.permissions.dataset.dto; import lombok.Data; +import lombok.EqualsAndHashCode; /** * @Author gin * @Date 2022/7/19 20:23 */ +@EqualsAndHashCode(callSuper = true) @Data public class DatasetRowPermissionsTreeRequest extends DataSetRowPermissionsTreeDTO { public String orderBy; diff --git a/sdk/api/api-permissions/src/main/java/io/dataease/api/permissions/role/vo/RoleDetailVO.java b/sdk/api/api-permissions/src/main/java/io/dataease/api/permissions/role/vo/RoleDetailVO.java index cc712d1e98..ec53c0d7f7 100644 --- a/sdk/api/api-permissions/src/main/java/io/dataease/api/permissions/role/vo/RoleDetailVO.java +++ b/sdk/api/api-permissions/src/main/java/io/dataease/api/permissions/role/vo/RoleDetailVO.java @@ -5,7 +5,9 @@ import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import io.dataease.api.permissions.role.dto.RoleCreator; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; +import lombok.EqualsAndHashCode; +@EqualsAndHashCode(callSuper = true) @Schema(description = "角色详情VO") @Data public class RoleDetailVO extends RoleCreator { diff --git a/sdk/api/api-permissions/src/main/java/io/dataease/api/permissions/user/dto/UserEditor.java b/sdk/api/api-permissions/src/main/java/io/dataease/api/permissions/user/dto/UserEditor.java index d108aabcc2..614072e687 100644 --- a/sdk/api/api-permissions/src/main/java/io/dataease/api/permissions/user/dto/UserEditor.java +++ b/sdk/api/api-permissions/src/main/java/io/dataease/api/permissions/user/dto/UserEditor.java @@ -2,9 +2,11 @@ package io.dataease.api.permissions.user.dto; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; +import lombok.EqualsAndHashCode; import java.io.Serial; +@EqualsAndHashCode(callSuper = true) @Schema(description = "用户编辑器") @Data public class UserEditor extends UserCreator{ diff --git a/sdk/api/api-sync/pom.xml b/sdk/api/api-sync/pom.xml new file mode 100644 index 0000000000..240a25c022 --- /dev/null +++ b/sdk/api/api-sync/pom.xml @@ -0,0 +1,20 @@ + + + + api + io.dataease + ${dataease.version} + + 4.0.0 + + api-sync + + + 17 + 17 + UTF-8 + + + diff --git a/sdk/api/api-sync/src/main/java/io/dataease/api/sync/datasource/api/SyncDatasourceApi.java b/sdk/api/api-sync/src/main/java/io/dataease/api/sync/datasource/api/SyncDatasourceApi.java new file mode 100644 index 0000000000..4e5d7c6cd5 --- /dev/null +++ b/sdk/api/api-sync/src/main/java/io/dataease/api/sync/datasource/api/SyncDatasourceApi.java @@ -0,0 +1,80 @@ +package io.dataease.api.sync.datasource.api; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import io.dataease.api.sync.datasource.dto.DBTableDTO; +import io.dataease.api.sync.datasource.dto.GetDatasourceRequest; +import io.dataease.api.sync.datasource.dto.SyncDatasourceDTO; +import io.dataease.api.sync.datasource.vo.SyncDatasourceVO; +import io.dataease.auth.DeApiPath; +import io.dataease.auth.DePermit; +import io.dataease.exception.DEException; +import io.dataease.request.BaseGridRequest; +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 java.util.List; +import java.util.Map; + +import static io.dataease.constant.AuthResourceEnum.SYNC_DATASOURCE; + +/** + * @author fit2cloud + * @date 2023/11/20 10:14 + **/ +@DeApiPath(value = "/sync/datasource", rt = SYNC_DATASOURCE) +public interface SyncDatasourceApi { + + @DePermit("m:read") + @PostMapping("/source/pager/{goPage}/{pageSize}") + IPage sourcePager(@PathVariable("goPage") int goPage, @PathVariable("pageSize") int pageSize, @RequestBody BaseGridRequest request); + + @DePermit("m:read") + @PostMapping("/target/pager/{goPage}/{pageSize}") + IPage targetPager(@PathVariable("goPage") int goPage, @PathVariable("pageSize") int pageSize, @RequestBody BaseGridRequest request); + + @PostMapping("/save") + void save(@RequestBody SyncDatasourceDTO dataSourceDTO) throws DEException; + + @PostMapping("/update") + void update(@RequestBody SyncDatasourceDTO dataSourceDTO) throws DEException; + + @PostMapping("/delete/{datasourceId}") + void delete(@PathVariable("datasourceId") String datasourceId) throws DEException; + + @GetMapping("/types") + Object datasourceTypes() throws DEException; + + @PostMapping("/validate") + String validate(@RequestBody SyncDatasourceDTO dataSourceDTO) throws DEException; + + @PostMapping("/getSchema") + List getSchema(@RequestBody SyncDatasourceDTO dataSourceDTO) throws DEException; + + @DePermit({"#p0+':manage'"}) + @GetMapping("/validate/{datasourceId}") + SyncDatasourceDTO validate(@PathVariable("datasourceId") String datasourceId) throws DEException; + + @PostMapping("/latestUse") + List latestUse(); + + @GetMapping("/get/{datasourceId}") + SyncDatasourceDTO get(@PathVariable("datasourceId") String datasourceId) throws DEException; + + @PostMapping("/batchDel") + void batchDel(@RequestBody List ids) throws DEException; + + @PostMapping("/fields") + Map getFields(@RequestBody GetDatasourceRequest getDsRequest) throws DEException ; + + @GetMapping("/list/{type}") + List listByType(@PathVariable("type") String type) throws DEException; + + @GetMapping("/table/list/{dsId}") + List getTableList(@PathVariable("dsId") String dsId) throws DEException; + + + + +} diff --git a/sdk/api/api-sync/src/main/java/io/dataease/api/sync/datasource/dto/DBTableDTO.java b/sdk/api/api-sync/src/main/java/io/dataease/api/sync/datasource/dto/DBTableDTO.java new file mode 100644 index 0000000000..a8112d8e26 --- /dev/null +++ b/sdk/api/api-sync/src/main/java/io/dataease/api/sync/datasource/dto/DBTableDTO.java @@ -0,0 +1,18 @@ +package io.dataease.api.sync.datasource.dto; + +import lombok.Getter; +import lombok.Setter; + +/** + * @Author gin + * @Date 2021/4/30 10:57 上午 + */ +@Getter +@Setter +public class DBTableDTO { + private String datasourceId; + private String name; + private String remark; + private boolean enableCheck; + private String datasetPath; +} diff --git a/sdk/api/api-sync/src/main/java/io/dataease/api/sync/datasource/dto/GetDatasourceRequest.java b/sdk/api/api-sync/src/main/java/io/dataease/api/sync/datasource/dto/GetDatasourceRequest.java new file mode 100644 index 0000000000..7387082ca2 --- /dev/null +++ b/sdk/api/api-sync/src/main/java/io/dataease/api/sync/datasource/dto/GetDatasourceRequest.java @@ -0,0 +1,25 @@ +package io.dataease.api.sync.datasource.dto; + +import lombok.Data; + +@Data +public class GetDatasourceRequest extends SyncDatasourceDTO { + + /** + * 查询sql + */ + private String query; + /** + * 表名 + */ + private String table; + /** + * 表格的抽取数据方式 + */ + private boolean tableExtract; + /** + * 不为空时,获取源数据库表字段,将转换为doris的数据类型 + */ + private String targetDbType; + +} diff --git a/sdk/api/api-sync/src/main/java/io/dataease/api/sync/datasource/dto/SyncDatasourceDTO.java b/sdk/api/api-sync/src/main/java/io/dataease/api/sync/datasource/dto/SyncDatasourceDTO.java new file mode 100644 index 0000000000..8c8146f655 --- /dev/null +++ b/sdk/api/api-sync/src/main/java/io/dataease/api/sync/datasource/dto/SyncDatasourceDTO.java @@ -0,0 +1,61 @@ +package io.dataease.api.sync.datasource.dto; + +import lombok.Data; + +/** + * @author fit2cloud + * @date 2023/11/20 11:14 + **/ +@Data +public class SyncDatasourceDTO { + + /** + * ID + */ + private String id; + + /** + * 名称 + */ + private String name; + + /** + * 描述 + */ + private String desc; + + /** + * 类型 + */ + private String type; + + /** + * 详细信息 + */ + private String configuration; + + /** + * Create timestamp + */ + private Long createTime; + + /** + * Update timestamp + */ + private Long updateTime; + + /** + * 创建人ID + */ + private Long createBy; + private String createByUserName; + + /** + * 状态 + */ + private String status; + + private String statusRemark; + + +} diff --git a/sdk/api/api-sync/src/main/java/io/dataease/api/sync/datasource/vo/SyncDatasourceVO.java b/sdk/api/api-sync/src/main/java/io/dataease/api/sync/datasource/vo/SyncDatasourceVO.java new file mode 100644 index 0000000000..385b8a94ee --- /dev/null +++ b/sdk/api/api-sync/src/main/java/io/dataease/api/sync/datasource/vo/SyncDatasourceVO.java @@ -0,0 +1,57 @@ +package io.dataease.api.sync.datasource.vo; + +import lombok.Data; + +/** + * @author fit2cloud + * @date 2023/11/20 11:18 + **/ +@Data +public class SyncDatasourceVO { + /** + * ID + */ + private String id; + + /** + * 名称 + */ + private String name; + + /** + * 描述 + */ + private String desc; + + /** + * 类型 + */ + private String type; + + /** + * 详细信息 + */ + private String configuration; + + /** + * Create timestamp + */ + private Long createTime; + + /** + * Update timestamp + */ + private Long updateTime; + + /** + * 创建人 + */ + private Long createBy; + private String createByName; + + /** + * 状态 + */ + private String status; + private String statusRemark; +} diff --git a/sdk/api/api-sync/src/main/java/io/dataease/api/sync/summary/api/SummaryApi.java b/sdk/api/api-sync/src/main/java/io/dataease/api/sync/summary/api/SummaryApi.java new file mode 100644 index 0000000000..9e83033c18 --- /dev/null +++ b/sdk/api/api-sync/src/main/java/io/dataease/api/sync/summary/api/SummaryApi.java @@ -0,0 +1,26 @@ +package io.dataease.api.sync.summary.api; + +import io.dataease.auth.DeApiPath; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; + +import java.util.Map; + +import static io.dataease.constant.AuthResourceEnum.SUMMARY; + +/** + * @author fit2cloud + * @date 2023/12/4 12:43 + **/ +@DeApiPath(value = "/sync/summary", rt = SUMMARY) +public interface SummaryApi { + + @GetMapping("/resourceCount") + Map resourceCount(); + + @PostMapping("/logChartData") + Map logChartData(@RequestBody String executeTaskLogDate); + + +} diff --git a/sdk/api/api-sync/src/main/java/io/dataease/api/sync/task/api/TaskApi.java b/sdk/api/api-sync/src/main/java/io/dataease/api/sync/task/api/TaskApi.java new file mode 100644 index 0000000000..f272b1a919 --- /dev/null +++ b/sdk/api/api-sync/src/main/java/io/dataease/api/sync/task/api/TaskApi.java @@ -0,0 +1,52 @@ +package io.dataease.api.sync.task.api; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import io.dataease.api.sync.task.dto.TaskInfoDTO; +import io.dataease.api.sync.task.vo.TaskInfoVO; +import io.dataease.auth.DeApiPath; +import io.dataease.exception.DEException; +import io.dataease.request.BaseGridRequest; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +import static io.dataease.constant.AuthResourceEnum.TASK; + +/** + * @author fit2cloud + * @date 2023/11/20 10:14 + **/ +@DeApiPath(value = "/sync/task", rt = TASK) +public interface TaskApi { + + @PostMapping("/pager/{goPage}/{pageSize}") + IPage pager(@PathVariable("goPage") int goPage, @PathVariable("pageSize") int pageSize, @RequestBody BaseGridRequest request); + + @PostMapping("/add") + void add(@RequestBody TaskInfoDTO jobInfo) throws DEException; + + @PostMapping("/update") + void update(@RequestBody TaskInfoDTO jobInfo) throws DEException; + + @DeleteMapping("/remove/{id}") + void remove(@PathVariable(value = "id") String id) throws DEException; + + @GetMapping("start/{id}") + void startJob(@PathVariable(value = "id") String id) throws DEException; + + @GetMapping("stop/{id}") + void stopJob(@PathVariable(value = "id") String id) throws DEException; + + @GetMapping("/get/{id}") + TaskInfoVO getOneById(@PathVariable(value = "id") String id) throws DEException; + + @GetMapping("/execute/{id}") + void execute(@PathVariable(value = "id") String id) throws DEException; + + @PostMapping("/batch/del") + void batchDelete(@RequestBody List ids) throws DEException; + + @GetMapping("/count") + Long count() throws DEException; + +} diff --git a/sdk/api/api-sync/src/main/java/io/dataease/api/sync/task/api/TaskLogApi.java b/sdk/api/api-sync/src/main/java/io/dataease/api/sync/task/api/TaskLogApi.java new file mode 100644 index 0000000000..925eec1254 --- /dev/null +++ b/sdk/api/api-sync/src/main/java/io/dataease/api/sync/task/api/TaskLogApi.java @@ -0,0 +1,39 @@ +package io.dataease.api.sync.task.api; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import io.dataease.api.sync.task.vo.LogResultVO; +import io.dataease.api.sync.task.vo.TaskLogVO; +import io.dataease.auth.DeApiPath; +import io.dataease.request.BaseGridRequest; +import org.springframework.web.bind.annotation.*; + +import static io.dataease.constant.AuthResourceEnum.TASK_LOG; + +/** + * @author fit2cloud + * @date 2023/12/4 12:43 + **/ +@DeApiPath(value = "/sync/task/log", rt = TASK_LOG) +public interface TaskLogApi { + @PostMapping("/pager/{goPage}/{pageSize}") + IPage pager(@PathVariable("goPage") int goPage, @PathVariable("pageSize") int pageSize, @RequestBody BaseGridRequest request); + + @GetMapping("/detail/{logId}/{fromLineNum}") + LogResultVO logDetail(@PathVariable("logId") String logId, @PathVariable("fromLineNum") int fromLineNum); + + @PostMapping("/save") + void saveLog(@RequestBody TaskLogVO logDetail); + + @PostMapping("/update") + void updateLog(@RequestBody TaskLogVO logDetail); + + @DeleteMapping("/deleteByJobId/{jobId}") + void deleteByJobId(@PathVariable("jobId") String jobId); + + @DeleteMapping("/delete/{logId}") + void deleteById(@PathVariable("logId") String logId); + + @PostMapping("/clear") + void clearJobLog(@RequestBody TaskLogVO taskLogVO); + +} diff --git a/sdk/api/api-sync/src/main/java/io/dataease/api/sync/task/dto/Source.java b/sdk/api/api-sync/src/main/java/io/dataease/api/sync/task/dto/Source.java new file mode 100644 index 0000000000..6c7c908c17 --- /dev/null +++ b/sdk/api/api-sync/src/main/java/io/dataease/api/sync/task/dto/Source.java @@ -0,0 +1,23 @@ +package io.dataease.api.sync.task.dto; + +import io.dataease.api.sync.datasource.dto.SyncDatasourceDTO; +import lombok.Data; + +import java.util.List; + + +/** + * @author fit2cloud + * @date 2023/8/10 16:38 + **/ +@Data +public class Source { + private String type; + private String query; + private String tables; + private SyncDatasourceDTO datasource; + private String datasourceId; + private String tableExtract; + private List fieldList; + private String incrementField; +} diff --git a/sdk/api/api-sync/src/main/java/io/dataease/api/sync/task/dto/TableField.java b/sdk/api/api-sync/src/main/java/io/dataease/api/sync/task/dto/TableField.java new file mode 100644 index 0000000000..cdeaabd91d --- /dev/null +++ b/sdk/api/api-sync/src/main/java/io/dataease/api/sync/task/dto/TableField.java @@ -0,0 +1,26 @@ +package io.dataease.api.sync.task.dto; + +import lombok.Getter; +import lombok.Setter; + +/** + * @author fit2cloud + */ +@Setter +@Getter +public class TableField { + private String fieldSource; + private String fieldName; + private String remarks; + private String fieldType; + private int fieldSize; + /** + * 精度 + */ + private int fieldPrecision; + + private boolean fieldPk; + private boolean fieldIndex; + private Object defaultValue; + +} diff --git a/sdk/api/api-sync/src/main/java/io/dataease/api/sync/task/dto/Target.java b/sdk/api/api-sync/src/main/java/io/dataease/api/sync/task/dto/Target.java new file mode 100644 index 0000000000..66ab74ea5d --- /dev/null +++ b/sdk/api/api-sync/src/main/java/io/dataease/api/sync/task/dto/Target.java @@ -0,0 +1,21 @@ +package io.dataease.api.sync.task.dto; + +import io.dataease.api.sync.datasource.dto.SyncDatasourceDTO; +import lombok.Data; + +import java.util.List; + +/** + * @author fit2cloud + * @date 2023/8/10 16:39 + **/ +@Data +public class Target { + private String type; + private String createTable; + private List fieldList; + private String tableName; + private SyncDatasourceDTO datasource; + private String datasourceId; + private String targetProperty; +} diff --git a/sdk/api/api-sync/src/main/java/io/dataease/api/sync/task/dto/TaskInfoDTO.java b/sdk/api/api-sync/src/main/java/io/dataease/api/sync/task/dto/TaskInfoDTO.java new file mode 100644 index 0000000000..03c05a7869 --- /dev/null +++ b/sdk/api/api-sync/src/main/java/io/dataease/api/sync/task/dto/TaskInfoDTO.java @@ -0,0 +1,112 @@ +package io.dataease.api.sync.task.dto; + +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * @author fit2cloud + * @date 2023/11/28 17:17 + **/ +@Data +public class TaskInfoDTO { + private String id; + + private String name; + + /** + * 任务类型KEY + */ + private String jobKey; + + private String desc; + + private LocalDateTime createTime; + + private LocalDateTime modifyTime; + + /** + * 创建人 + */ + private Long createBy; + + /** + * 修改人 + */ + private Long modifyBy; + + /** + * 任务参数 + */ + private String parameter; + + /** + * 扩展参数 + */ + private String extParameter; + + /** + * 当前任务状态 + * unexecuted未执行 currentTime=currentTime>=startTime,status=1 + * suspend暂停 stopTime>=currentTime>=startTime,status=0 + * done执行结束 currentTime>stopTime + * running执行中,通过当前任务的日志状态判断,如果有日志在执行中 + */ + private String status; + + /** + * 删除标识 + */ + private Boolean deleted; + + /** + * 任务执行超时时间 + */ + private Long executorTimeout; + + /** + * 任务执行失败重试次数 + */ + private Long executorFailRetryCount; + + /** + * 上次调度时间 + */ + private Long triggerLastTime; + + /** + * 下次次调度时间 + */ + private Long triggerNextTime; + + /** + * 调度类型,NONE,CRON,FIX_RATE,FIX_DELAY + */ + private String schedulerType; + + /** + * 调度配置,取决于调度类型 + */ + private String schedulerConf; + + /** + * 开始时间 + */ + private String startTime; + + /** + * 结束时间 + */ + private String stopTime; + + + /** + * 源数据源信息 + */ + private Source source; + /** + * 目标数据源信息 + */ + private Target target; +} diff --git a/sdk/api/api-sync/src/main/java/io/dataease/api/sync/task/vo/LogResultVO.java b/sdk/api/api-sync/src/main/java/io/dataease/api/sync/task/vo/LogResultVO.java new file mode 100644 index 0000000000..f69791bfc3 --- /dev/null +++ b/sdk/api/api-sync/src/main/java/io/dataease/api/sync/task/vo/LogResultVO.java @@ -0,0 +1,44 @@ +package io.dataease.api.sync.task.vo; + +import lombok.Getter; +import lombok.Setter; + +/** + * 日志返回结果 + * + * @author fit2cloud + */ +@Getter +@Setter +public class LogResultVO { + + /** + * 日志开始行号 + */ + private int fromLineNum; + /** + * 日志结束行号 + */ + private int toLineNum; + /** + * 日志内容 + */ + private String logContent; + /** + * 是否是最后一行 + */ + private boolean isEnd; + + public LogResultVO() { + + } + + public LogResultVO(int fromLineNum, int toLineNum, String logContent, boolean isEnd) { + this.fromLineNum = fromLineNum; + this.toLineNum = toLineNum; + this.logContent = logContent; + this.isEnd = isEnd; + } + + +} diff --git a/sdk/api/api-sync/src/main/java/io/dataease/api/sync/task/vo/TaskInfoVO.java b/sdk/api/api-sync/src/main/java/io/dataease/api/sync/task/vo/TaskInfoVO.java new file mode 100644 index 0000000000..e814ac3fd5 --- /dev/null +++ b/sdk/api/api-sync/src/main/java/io/dataease/api/sync/task/vo/TaskInfoVO.java @@ -0,0 +1,132 @@ +package io.dataease.api.sync.task.vo; + +import io.dataease.api.sync.task.dto.Source; +import io.dataease.api.sync.task.dto.Target; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * @author fit2cloud + * @date 2023/11/28 17:15 + **/ +@Data +public class TaskInfoVO { + + private String id; + + private String name; + + /** + * 任务类型KEY + */ + private String jobKey; + + private String desc; + + private LocalDateTime createTime; + + private LocalDateTime modifyTime; + + /** + * 创建人 + */ + private Long createBy;; + /** + * 创建人 + */ + private String userName; + + /** + * 任务参数 + */ + private String parameter; + + /** + * 扩展参数 + */ + private String extParameter; + + /** + * 任务状态 + * unexecuted未执行 currentTime=currentTime>=startTime,status=1 + * suspend暂停 stopTime>=currentTime>=startTime,status=0 + * done执行结束 currentTime>stopTime + * running执行中,通过当前任务的日志状态判断,如果有日志在执行中 + */ + private String status; + + /** + * 删除标识 + */ + private Boolean deleted; + + /** + * 任务执行超时时间 + */ + private Long executorTimeout; + + /** + * 任务执行失败重试次数 + */ + private Long executorFailRetryCount; + + /** + * 上次调度时间 + */ + private Long triggerLastTime; + + /** + * 下次次调度时间 + */ + private Long triggerNextTime; + + /** + * 调度类型,NONE,CRON,FIX_RATE,FIX_DELAY + */ + private String schedulerType; + + /** + * 调度配置,取决于调度类型 + */ + private String schedulerConf; + + /** + * 开始时间 + */ + private Long startTime; + + /** + * 结束时间 + */ + private Long stopTime; + + private Source source; + private Target target; + + /** + * 上次执行结果,获取任务最新的日志状态 + * running执行中 + * success + * fail失败 + */ + private String lastExecuteStatus; + private Long incrementValue; + + // 以下为日志信息 + private String logId; + private Long executorStartTime; + private Long executorEndTime; + private String executorMsg; + /** + * 成功SUCCESS,失败FAIL,执行中RUNNING + */ + private String logStatus; + + /** + * 在执行周期内 + */ + private boolean withinCycle; + +} diff --git a/sdk/api/api-sync/src/main/java/io/dataease/api/sync/task/vo/TaskLogVO.java b/sdk/api/api-sync/src/main/java/io/dataease/api/sync/task/vo/TaskLogVO.java new file mode 100644 index 0000000000..44289bc91a --- /dev/null +++ b/sdk/api/api-sync/src/main/java/io/dataease/api/sync/task/vo/TaskLogVO.java @@ -0,0 +1,25 @@ +package io.dataease.api.sync.task.vo; + +import lombok.Data; + +/** + * 任务日志 + * @author fit2cloud + * @date 2023/9/19 17:44 + **/ +@Data +public class TaskLogVO { + + private String id; + private String jobId; + private String jobName; + private String jobDesc; + private Long executorStartTime; + private Long executorEndTime; + private String status; + private String executorMsg; + private String executorAddress; + + private String clearType; + +} diff --git a/sdk/api/pom.xml b/sdk/api/pom.xml index 58186de6bd..d9f8c90c22 100644 --- a/sdk/api/pom.xml +++ b/sdk/api/pom.xml @@ -15,6 +15,7 @@ api-permissions api-base + api-sync diff --git a/sdk/common/src/main/java/io/dataease/auth/interceptor/CorsInterceptor.java b/sdk/common/src/main/java/io/dataease/auth/interceptor/CorsInterceptor.java index d53e809fcd..97078d3ac4 100644 --- a/sdk/common/src/main/java/io/dataease/auth/interceptor/CorsInterceptor.java +++ b/sdk/common/src/main/java/io/dataease/auth/interceptor/CorsInterceptor.java @@ -1,15 +1,17 @@ package io.dataease.auth.interceptor; -import cn.hutool.core.util.ReflectUtil; import io.dataease.utils.CommonBeanFactory; +import io.dataease.utils.DeReflectUtil; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Component; +import org.springframework.util.ReflectionUtils; import org.springframework.web.servlet.HandlerInterceptor; +import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; @@ -51,7 +53,8 @@ public class CorsInterceptor implements HandlerInterceptor { bean = CommonBeanFactory.getBean(aClass); } if (ObjectUtils.isNotEmpty(bean)) { - Object result = ReflectUtil.invoke(bean, methodName); + Method method = DeReflectUtil.findMethod(aClass, methodName); + Object result = ReflectionUtils.invokeMethod(method, bean); if (ObjectUtils.isNotEmpty(result)) { List list = (List) result; if (CollectionUtils.isNotEmpty(list)) { diff --git a/sdk/common/src/main/java/io/dataease/constant/AuthResourceEnum.java b/sdk/common/src/main/java/io/dataease/constant/AuthResourceEnum.java index 093f3835ad..60270644d1 100644 --- a/sdk/common/src/main/java/io/dataease/constant/AuthResourceEnum.java +++ b/sdk/common/src/main/java/io/dataease/constant/AuthResourceEnum.java @@ -2,7 +2,7 @@ package io.dataease.constant; public enum AuthResourceEnum { - PANEL(2, 1), SCREEN(3, 2), DATASET(5, 3), DATASOURCE(6, 4), SYSTEM(7, 0), USER(8, 5), ROLE(8, 6), ORG(9, 7); + PANEL(2, 1), SCREEN(3, 2), DATASET(5, 3), DATASOURCE(6, 4), SYSTEM(7, 0), USER(8, 5), ROLE(8, 6), ORG(9, 7), SYNC_DATASOURCE(10, 8), TASK(11, 9),TASK_LOG(12, 10), SUMMARY(13, 11); private long menuId; diff --git a/sdk/common/src/main/java/io/dataease/constant/XpackSettingConstants.java b/sdk/common/src/main/java/io/dataease/constant/XpackSettingConstants.java index d8e7585343..6b8b760a6d 100644 --- a/sdk/common/src/main/java/io/dataease/constant/XpackSettingConstants.java +++ b/sdk/common/src/main/java/io/dataease/constant/XpackSettingConstants.java @@ -3,4 +3,5 @@ package io.dataease.constant; public class XpackSettingConstants { public static final String AUTO_CREATE_USER = "basic.autoCreateUser"; + public static final String Front_Time_Out = "basic.frontTimeOut"; } diff --git a/sdk/common/src/main/java/io/dataease/doc/SwaggerConfig.java b/sdk/common/src/main/java/io/dataease/doc/SwaggerConfig.java index 52e38fbeee..09f55c0926 100644 --- a/sdk/common/src/main/java/io/dataease/doc/SwaggerConfig.java +++ b/sdk/common/src/main/java/io/dataease/doc/SwaggerConfig.java @@ -1,9 +1,9 @@ package io.dataease.doc; -import cn.hutool.core.util.RandomUtil; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.info.Contact; import io.swagger.v3.oas.models.info.Info; +import org.apache.commons.lang3.RandomUtils; import org.springdoc.core.customizers.GlobalOpenApiCustomizer; import org.springdoc.core.models.GroupedOpenApi; import org.springframework.beans.factory.annotation.Value; @@ -22,10 +22,10 @@ public class SwaggerConfig { @Bean public GlobalOpenApiCustomizer orderGlobalOpenApiCustomizer() { return openApi -> { - if (openApi.getTags()!=null){ + if (openApi.getTags() != null) { openApi.getTags().forEach(tag -> { - Map map=new HashMap<>(); - map.put("x-order", RandomUtil.randomInt(0,100)); + Map map = new HashMap<>(); + map.put("x-order", RandomUtils.nextInt(0, 100)); tag.setExtensions(map); }); } @@ -48,7 +48,6 @@ public class SwaggerConfig { } - @Bean public GroupedOpenApi visualizationApi() { return GroupedOpenApi.builder().group("1-visualization").displayName("可视化管理").packagesToScan("io.dataease.visualization").build(); @@ -89,6 +88,4 @@ public class SwaggerConfig { } - - } diff --git a/sdk/common/src/main/java/io/dataease/utils/DeReflectUtil.java b/sdk/common/src/main/java/io/dataease/utils/DeReflectUtil.java new file mode 100644 index 0000000000..3a261e1b40 --- /dev/null +++ b/sdk/common/src/main/java/io/dataease/utils/DeReflectUtil.java @@ -0,0 +1,19 @@ +package io.dataease.utils; + +import org.apache.commons.lang3.ArrayUtils; + +import java.lang.reflect.Method; + +public class DeReflectUtil { + + public static Method findMethod(Class> cla, String methodName) { + Method[] methods = cla.getMethods(); + if (ArrayUtils.isEmpty(methods)) return null; + for (Method method : methods) { + if (method.getName().equals(methodName)){ + return method; + } + } + return null; + } +} diff --git a/sdk/common/src/main/java/io/dataease/utils/IDUtils.java b/sdk/common/src/main/java/io/dataease/utils/IDUtils.java index e27dd4feed..e362279d63 100644 --- a/sdk/common/src/main/java/io/dataease/utils/IDUtils.java +++ b/sdk/common/src/main/java/io/dataease/utils/IDUtils.java @@ -1,18 +1,20 @@ package io.dataease.utils; -import cn.hutool.core.util.IdUtil; -import cn.hutool.core.util.RandomUtil; + import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.RandomStringUtils; public class IDUtils { + private static SnowFlake snowFlake = new SnowFlake(1, 1); + public static String randomID(Integer num) { num = ObjectUtils.isEmpty(num) ? 16 : num; - return RandomUtil.randomString(16); + return RandomStringUtils.randomAlphanumeric(num); } // 主键请不要使用字符串 推荐雪花算法 public static Long snowID() { - return IdUtil.getSnowflakeNextId(); + return snowFlake.nextId(); } } diff --git a/sdk/common/src/main/java/io/dataease/utils/RsaUtils.java b/sdk/common/src/main/java/io/dataease/utils/RsaUtils.java index 93c5f1c843..b5c781a9a7 100644 --- a/sdk/common/src/main/java/io/dataease/utils/RsaUtils.java +++ b/sdk/common/src/main/java/io/dataease/utils/RsaUtils.java @@ -1,23 +1,42 @@ package io.dataease.utils; -import cn.hutool.core.util.RandomUtil; -import cn.hutool.crypto.asymmetric.KeyType; -import cn.hutool.crypto.asymmetric.RSA; -import cn.hutool.crypto.symmetric.AES; + +import io.dataease.exception.DEException; import io.dataease.model.RSAModel; import io.dataease.rsa.dao.entity.CoreRsa; import io.dataease.rsa.manage.RsaManage; import jakarta.annotation.Resource; -import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.RandomStringUtils; import org.springframework.stereotype.Component; import org.springframework.util.Base64Utils; +import javax.crypto.Cipher; +import javax.crypto.SecretKey; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.io.ByteArrayOutputStream; import java.nio.charset.StandardCharsets; -import java.security.Security; +import java.security.*; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; @Component public class RsaUtils { + static { + if (ObjectUtils.isNotEmpty(Security.getProvider("BC"))) { + Security.removeProvider("BC"); + } + Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); + } + + + private static final int MAX_ENCRYPT_BLOCK = 117; + + private static final int MAX_DECRYPT_BLOCK = 128; + private static final String PK_SEPARATOR = "-pk_separator-"; private static RsaManage rsaManage; @@ -27,20 +46,108 @@ public class RsaUtils { RsaUtils.rsaManage = rsaManage; } + private static KeyPair getKeyPair() { + KeyPairGenerator generator = null; + try { + generator = KeyPairGenerator.getInstance("RSA"); + } catch (NoSuchAlgorithmException e) { + LogUtil.error(e.getMessage(), e); + DEException.throwException(e); + } + generator.initialize(1024); + return generator.generateKeyPair(); + } + + private static PrivateKey getPrivateKey(String privateKey) { + KeyFactory keyFactory = null; + try { + keyFactory = KeyFactory.getInstance("RSA"); + byte[] decodedKey = Base64.decodeBase64(privateKey.getBytes()); + PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(decodedKey); + return keyFactory.generatePrivate(keySpec); + } catch (Exception e) { + LogUtil.error(e.getMessage(), e); + throw new RuntimeException(e); + } + } + + private static PublicKey getPublicKey(String publicKey) { + KeyFactory keyFactory = null; + try { + keyFactory = KeyFactory.getInstance("RSA"); + byte[] decodedKey = Base64.decodeBase64(publicKey.getBytes()); + X509EncodedKeySpec keySpec = new X509EncodedKeySpec(decodedKey); + return keyFactory.generatePublic(keySpec); + } catch (Exception e) { + LogUtil.error(e.getMessage(), e); + throw new RuntimeException(e); + } + } + + private static String encrypt(String data, PublicKey publicKey) throws Exception { + Cipher cipher = Cipher.getInstance("RSA"); + cipher.init(Cipher.ENCRYPT_MODE, publicKey); + int inputLen = data.getBytes().length; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + int offset = 0; + byte[] cache; + int i = 0; + while (inputLen - offset > 0) { + if (inputLen - offset > MAX_ENCRYPT_BLOCK) { + cache = cipher.doFinal(data.getBytes(), offset, MAX_ENCRYPT_BLOCK); + } else { + cache = cipher.doFinal(data.getBytes(), offset, inputLen - offset); + } + out.write(cache, 0, cache.length); + i++; + offset = i * MAX_ENCRYPT_BLOCK; + } + byte[] encryptedData = out.toByteArray(); + out.close(); + return Base64.encodeBase64String(encryptedData); + } + + private static String decrypt(String data, PrivateKey privateKey) throws Exception { + Cipher cipher = Cipher.getInstance("RSA"); + cipher.init(Cipher.DECRYPT_MODE, privateKey); + byte[] dataBytes = Base64.decodeBase64(data); + int inputLen = dataBytes.length; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + int offset = 0; + byte[] cache; + int i = 0; + while (inputLen - offset > 0) { + if (inputLen - offset > MAX_DECRYPT_BLOCK) { + cache = cipher.doFinal(dataBytes, offset, MAX_DECRYPT_BLOCK); + } else { + cache = cipher.doFinal(dataBytes, offset, inputLen - offset); + } + out.write(cache, 0, cache.length); + i++; + offset = i * MAX_DECRYPT_BLOCK; + } + out.close(); + return out.toString(StandardCharsets.UTF_8); + } + public static RSAModel generate() { - RSA rsa = new RSA(); - String privateKeyBase64 = rsa.getPrivateKeyBase64(); - String publicKeyBase64 = rsa.getPublicKeyBase64(); + KeyPair keyPair = getKeyPair(); + String privateKey = new String(Base64.encodeBase64(keyPair.getPrivate().getEncoded())); + String publicKey = new String(Base64.encodeBase64(keyPair.getPublic().getEncoded())); RSAModel rsaModel = new RSAModel(); - rsaModel.setPrivateKey(privateKeyBase64); - rsaModel.setPublicKey(publicKeyBase64); + rsaModel.setPrivateKey(privateKey); + rsaModel.setPublicKey(publicKey); rsaModel.setAesKey(generateAesKey()); return rsaModel; } public static String decryptStr(String data, String privateKey) { - RSA rsa = new RSA(privateKey, null); - return rsa.decryptStr(data, KeyType.PrivateKey); + try { + return decrypt(data, getPrivateKey(privateKey)); + } catch (Exception e) { + LogUtil.error(e.getMessage(), e); + throw new RuntimeException(e); + } } public static String decryptStr(String data) { @@ -48,8 +155,12 @@ public class RsaUtils { } public static String encryptStr(String data) { - RSA rsa = new RSA(privateKey(), publicKey()); - return rsa.encryptBase64(data, KeyType.PublicKey); + try { + return encrypt(data, getPublicKey(publicKey())); + } catch (Exception e) { + LogUtil.error(e.getMessage(), e); + throw new RuntimeException(e); + } } public static String privateKey() { @@ -61,23 +172,40 @@ public class RsaUtils { CoreRsa coreRsa = rsaManage.query(); String publicKey = coreRsa.getPublicKey(); String aesKey = coreRsa.getAesKey(); - // Security.addProvider(new BouncyCastleProvider()); - String pk = ascEncrypt(publicKey, aesKey); + String pk = ascEncrypt(publicKey, aesKey).replaceAll("[\\s*\t\n\r]", ""); String separator = Base64Utils.encodeToUrlSafeString(PK_SEPARATOR.getBytes(StandardCharsets.UTF_8)); return pk + separator + aesKey; } private static final String IV_KEY = "0000000000000000"; + private static String generateAesKey() { - return RandomUtil.randomString(16); + return RandomStringUtils.randomAlphanumeric(16); } + private static String ascEncrypt(String message, String key) { - byte[] baseKey = key.getBytes(StandardCharsets.UTF_8); + /*byte[] baseKey = key.getBytes(StandardCharsets.UTF_8); byte[] ivBytes = IV_KEY.getBytes(StandardCharsets.UTF_8); AES aes = new AES("CBC", "PKCS7Padding", baseKey, ivBytes); byte[] messageBytes = message.getBytes(StandardCharsets.UTF_8); - return Base64Utils.encodeToString(aes.encrypt(messageBytes)); + return Base64Utils.encodeToString(aes.encrypt(messageBytes));*/ + + Cipher cipher = null; + try { + byte[] baseKey = key.getBytes(StandardCharsets.UTF_8); + byte[] ivBytes = IV_KEY.getBytes(StandardCharsets.UTF_8); + byte[] messageBytes = message.getBytes(StandardCharsets.UTF_8); + cipher = Cipher.getInstance("AES/CBC/PKCS7Padding"); + // 根据secretKey(密钥)的字节内容,"恢复"秘钥对象 + SecretKey keySpec = new SecretKeySpec(baseKey, "AES"); + IvParameterSpec ivps = new IvParameterSpec(ivBytes); + cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivps); + byte[] data = cipher.doFinal(messageBytes); + return Base64.encodeBase64String(data); + } catch (Exception e) { + LogUtil.error(e.getMessage(), e); + throw new RuntimeException(e); + } + } - - } diff --git a/sdk/common/src/main/java/io/dataease/utils/SnowFlake.java b/sdk/common/src/main/java/io/dataease/utils/SnowFlake.java new file mode 100644 index 0000000000..e820f58e13 --- /dev/null +++ b/sdk/common/src/main/java/io/dataease/utils/SnowFlake.java @@ -0,0 +1,89 @@ +package io.dataease.utils; + +public class SnowFlake { + + /** + * 起始的时间戳 + */ + private final static long START_STMP = 1480166465631L; + + /** + * 每一部分占用的位数 + */ + private final static long SEQUENCE_BIT = 12; //序列号占用的位数 + private final static long MACHINE_BIT = 5; //机器标识占用的位数 + private final static long DATACENTER_BIT = 5;//数据中心占用的位数 + + /** + * 每一部分的最大值 + */ + private final static long MAX_DATACENTER_NUM = -1L ^ (-1L << DATACENTER_BIT); + private final static long MAX_MACHINE_NUM = -1L ^ (-1L << MACHINE_BIT); + private final static long MAX_SEQUENCE = -1L ^ (-1L << SEQUENCE_BIT); + + /** + * 每一部分向左的位移 + */ + private final static long MACHINE_LEFT = SEQUENCE_BIT; + private final static long DATACENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT; + private final static long TIMESTMP_LEFT = DATACENTER_LEFT + DATACENTER_BIT; + + private long datacenterId; //数据中心 + private long machineId; //机器标识 + private long sequence = 0L; //序列号 + private long lastStmp = -1L;//上一次时间戳 + + public SnowFlake(long datacenterId, long machineId) { + if (datacenterId > MAX_DATACENTER_NUM || datacenterId < 0) { + throw new IllegalArgumentException("datacenterId can't be greater than MAX_DATACENTER_NUM or less than 0"); + } + if (machineId > MAX_MACHINE_NUM || machineId < 0) { + throw new IllegalArgumentException("machineId can't be greater than MAX_MACHINE_NUM or less than 0"); + } + this.datacenterId = datacenterId; + this.machineId = machineId; + } + + /** + * 产生下一个ID + * + * @return + */ + public synchronized long nextId() { + long currStmp = getNewstmp(); + if (currStmp < lastStmp) { + throw new RuntimeException("Clock moved backwards. Refusing to generate id"); + } + + if (currStmp == lastStmp) { + //相同毫秒内,序列号自增 + sequence = (sequence + 1) & MAX_SEQUENCE; + //同一毫秒的序列数已经达到最大 + if (sequence == 0L) { + currStmp = getNextMill(); + } + } else { + //不同毫秒内,序列号置为0 + sequence = 0L; + } + + lastStmp = currStmp; + + return (currStmp - START_STMP) << TIMESTMP_LEFT //时间戳部分 + | datacenterId << DATACENTER_LEFT //数据中心部分 + | machineId << MACHINE_LEFT //机器标识部分 + | sequence; //序列号部分 + } + + private long getNextMill() { + long mill = getNewstmp(); + while (mill <= lastStmp) { + mill = getNewstmp(); + } + return mill; + } + + private long getNewstmp() { + return System.currentTimeMillis(); + } +} diff --git a/sdk/common/src/main/java/io/dataease/utils/StaticResourceUtils.java b/sdk/common/src/main/java/io/dataease/utils/StaticResourceUtils.java index 713f6e0d03..7736aa3e04 100644 --- a/sdk/common/src/main/java/io/dataease/utils/StaticResourceUtils.java +++ b/sdk/common/src/main/java/io/dataease/utils/StaticResourceUtils.java @@ -1,9 +1,10 @@ package io.dataease.utils; -import cn.hutool.core.codec.Base64Encoder; import org.apache.commons.lang3.StringUtils; import org.springframework.lang.NonNull; import org.springframework.util.Assert; +import org.springframework.util.Base64Utils; + import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; @@ -12,7 +13,7 @@ import static io.dataease.constant.StaticResourceConstants.*; public class StaticResourceUtils { - private final static String FILE_BASE_PATH = USER_HOME+ FILE_SEPARATOR+UPLOAD_URL_PREFIX; + private final static String FILE_BASE_PATH = USER_HOME + FILE_SEPARATOR + UPLOAD_URL_PREFIX; public static String ensureBoth(@NonNull String string, @NonNull String bothfix) { return ensureBoth(string, bothfix, bothfix); @@ -53,8 +54,7 @@ public class StaticResourceUtils { } /** - * - * @param imgFile local storage path + * @param imgFile local storage path * @return */ public static String getImgFileToBase64(String imgFile) { @@ -63,7 +63,7 @@ public class StaticResourceUtils { byte[] buffer = null; //Read picture byte array try { - inputStream = new FileInputStream(FILE_BASE_PATH+FILE_SEPARATOR+imgFile); + inputStream = new FileInputStream(FILE_BASE_PATH + FILE_SEPARATOR + imgFile); int count = 0; while (count == 0) { count = inputStream.available(); @@ -72,9 +72,9 @@ public class StaticResourceUtils { inputStream.read(buffer); } catch (IOException e) { LogUtil.error(e); - }catch (Exception e){ + } catch (Exception e) { LogUtil.error(e); - }finally { + } finally { if (inputStream != null) { try { // Close InputStream @@ -85,10 +85,9 @@ public class StaticResourceUtils { } } // Encode byte array as Base64 - if(buffer!=null){ - - return Base64Encoder.encode(buffer); - }else{ + if (buffer != null) { + return Base64Utils.encodeToString(buffer); + } else { return null; } } diff --git a/sdk/common/src/main/java/io/dataease/utils/SystemSettingUtils.java b/sdk/common/src/main/java/io/dataease/utils/SystemSettingUtils.java index 27676b29b3..9629897394 100644 --- a/sdk/common/src/main/java/io/dataease/utils/SystemSettingUtils.java +++ b/sdk/common/src/main/java/io/dataease/utils/SystemSettingUtils.java @@ -1,6 +1,5 @@ package io.dataease.utils; -import cn.hutool.core.collection.ListUtil; import io.dataease.constant.XpackSettingConstants; import java.util.List; @@ -8,7 +7,8 @@ import java.util.List; public class SystemSettingUtils { public static boolean xpackSetting(String pkey) { - List xpackSettingList = ListUtil.toList(XpackSettingConstants.AUTO_CREATE_USER); + + List xpackSettingList = List.of(XpackSettingConstants.AUTO_CREATE_USER); return xpackSettingList.contains(pkey); } } diff --git a/sdk/common/src/main/java/io/dataease/utils/TreeUtils.java b/sdk/common/src/main/java/io/dataease/utils/TreeUtils.java index 9e6ded00a5..d9e8f71182 100644 --- a/sdk/common/src/main/java/io/dataease/utils/TreeUtils.java +++ b/sdk/common/src/main/java/io/dataease/utils/TreeUtils.java @@ -1,14 +1,12 @@ package io.dataease.utils; -import cn.hutool.core.collection.CollectionUtil; import io.dataease.model.ITreeBase; import io.dataease.model.TreeBaseModel; import io.dataease.model.TreeModel; import io.dataease.model.TreeResultModel; +import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.ObjectUtils; -import org.apache.commons.lang3.StringUtils; import org.springframework.util.Assert; -import org.springframework.util.CollectionUtils; import java.util.ArrayList; import java.util.Arrays; @@ -38,21 +36,21 @@ public class TreeUtils { List existedList = new ArrayList<>(); modelList.forEach(po -> { List children = null; - if (CollectionUtil.isNotEmpty(children = childMap.get(po.getId()))) { + if (CollectionUtils.isNotEmpty(children = childMap.get(po.getId()))) { po.setChildren(children); existedList.addAll(children.stream().map(TreeModel::getId).toList()); } }); - if (CollectionUtil.isEmpty(modelList)) { + if (CollectionUtils.isEmpty(modelList)) { return null; } List floatingList = modelList.stream().filter(node -> !isRoot(node) && !existedList.contains(node.getId())).toList(); - if (CollectionUtil.isNotEmpty(existedList)) { + if (CollectionUtils.isNotEmpty(existedList)) { modelResult = modelList.stream().filter(node -> !existedList.contains(node.getId())).toList(); } else { modelResult = modelList; } - if (rootExist.get() && CollectionUtil.isNotEmpty(floatingList)) { + if (rootExist.get() && CollectionUtils.isNotEmpty(floatingList)) { modelResult = modelResult.stream().filter(TreeUtils::isRoot).collect(Collectors.toList()); TreeModel root = modelResult.get(0); if (root.getChildren() == null) { diff --git a/sdk/common/src/main/java/io/dataease/utils/WhitelistUtils.java b/sdk/common/src/main/java/io/dataease/utils/WhitelistUtils.java index e8f0c2a772..a6a88eb2c4 100644 --- a/sdk/common/src/main/java/io/dataease/utils/WhitelistUtils.java +++ b/sdk/common/src/main/java/io/dataease/utils/WhitelistUtils.java @@ -1,6 +1,5 @@ package io.dataease.utils; -import cn.hutool.core.collection.ListUtil; import io.dataease.constant.AuthConstant; import org.apache.commons.lang3.StringUtils; @@ -8,7 +7,7 @@ import java.util.List; public class WhitelistUtils { - public static List WHITE_PATH = ListUtil.of( + public static List WHITE_PATH = List.of( "/login/localLogin", "/apisix/check", "/dekey", @@ -19,6 +18,7 @@ public class WhitelistUtils { "/panel.html", "/lark/info", "/lark/token", + "/sysParameter/requestTimeOut", "/setting/authentication/status", "/");
+ * + *
+ * Mapper 接口 + *
- * 仪表板模板表 + * *
- * 仪表板模板表 Mapper 接口 + * Mapper 接口 *