diff --git a/README.md b/README.md index 4cbf7af671..39f54301c8 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ DataEase 是开源的数据可视化分析工具,帮助用户快速分析数据并洞察业务趋势,从而实现业务的改进与优化。DataEase 支持丰富的数据源连接,能够通过拖拉拽方式快速制作图表,并可以方便的与他人分享。

- DataEase 概览图 + DataEase 概览图

**DataEase 的优势:** diff --git a/core/core-backend/pom.xml b/core/core-backend/pom.xml index 202a279ec8..633c8177bd 100644 --- a/core/core-backend/pom.xml +++ b/core/core-backend/pom.xml @@ -5,7 +5,7 @@ core io.dataease - 2.0.0 + 2.1.0 4.0.0 @@ -92,6 +92,10 @@ + + com.h2database + h2 + 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 a4ca90c54a..21d99e6ed7 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 @@ -1106,11 +1106,11 @@ public class ChartDataBuild { break; } if (originStr.length() >= columnPermissionItem.getDesensitizationRule().getM() && originStr.length() >= columnPermissionItem.getDesensitizationRule().getN()) { - desensitizationStr = "***" + StringUtils.substring(originStr, columnPermissionItem.getDesensitizationRule().getM() - 1, columnPermissionItem.getDesensitizationRule().getN()) + "***"; + desensitizationStr = StringUtils.substring(originStr, columnPermissionItem.getDesensitizationRule().getM() - 1, columnPermissionItem.getDesensitizationRule().getN()) + "***"; break; } if (originStr.length() >= columnPermissionItem.getDesensitizationRule().getM() && originStr.length() < columnPermissionItem.getDesensitizationRule().getN()) { - desensitizationStr = "***" + StringUtils.substring(originStr, columnPermissionItem.getDesensitizationRule().getM() - 1, originStr.length()); + desensitizationStr = StringUtils.substring(originStr, columnPermissionItem.getDesensitizationRule().getM() - 1, originStr.length()); } break; default: diff --git a/core/core-backend/src/main/java/io/dataease/commons/constants/DataVisualizationConstants.java b/core/core-backend/src/main/java/io/dataease/commons/constants/DataVisualizationConstants.java index 25acbfd475..19cc6e310c 100644 --- a/core/core-backend/src/main/java/io/dataease/commons/constants/DataVisualizationConstants.java +++ b/core/core-backend/src/main/java/io/dataease/commons/constants/DataVisualizationConstants.java @@ -51,5 +51,13 @@ public class DataVisualizationConstants { public static final String COPY = "copy"; } + public static final class TEMPLATE_SOURCE { + //模板市场 + public static final String MARKET = "market"; + //模板管理 + public static final String MANAGE = "manage"; + //公共 + public static final String PUBLIC = "public"; + } } 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 3e07e263b4..7296453e33 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 @@ -33,14 +33,20 @@ import io.dataease.datasource.request.DatasourceRequest; import io.dataease.engine.constant.SQLConstants; import io.dataease.exception.DEException; import io.dataease.i18n.Translator; +import io.dataease.job.sechedule.CheckDsStatusJob; +import io.dataease.job.sechedule.ScheduleManager; import io.dataease.license.config.XpackInteract; import io.dataease.model.BusiNodeRequest; import io.dataease.model.BusiNodeVO; +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.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; @@ -85,7 +91,8 @@ public class DatasourceServer implements DatasourceApi { @Resource private DatasetDataManage datasetDataManage; - + @Resource + private ScheduleManager scheduleManager; @Resource private CoreUserManage coreUserManage; @@ -260,7 +267,7 @@ public class DatasourceServer implements DatasourceApi { try { datasourceSyncManage.createEngineTable(datasourceRequest.getTable(), tableFields); } catch (Exception e) { - DEException.throwException("Failed to create table " + datasourceRequest.getTable()); + DEException.throwException("Failed to create table " + datasourceRequest.getTable() + ", " + e.getMessage()); } } commonThreadPool.addTask(() -> { @@ -402,7 +409,7 @@ public class DatasourceServer implements DatasourceApi { try { datasourceSyncManage.createEngineTable(toCreateTable, ApiUtils.getTableFields(datasourceRequest)); } catch (Exception e) { - DEException.throwException("Failed to create table " + toCreateTable); + DEException.throwException("Failed to create table " + toCreateTable + ", " + e.getMessage()); } } datasourceSyncManage.deleteSchedule(datasourceTaskServer.selectByDSId(dataSourceDTO.getId())); @@ -418,7 +425,7 @@ public class DatasourceServer implements DatasourceApi { try { datasourceSyncManage.dropEngineTable(deleteTable); } catch (Exception e) { - DEException.throwException("Failed to drop table " + deleteTable); + DEException.throwException("Failed to drop table " + deleteTable + ", " + e.getMessage()); } } for (String toCreateTable : toCreateTables) { @@ -426,7 +433,7 @@ public class DatasourceServer implements DatasourceApi { try { datasourceSyncManage.createEngineTable(toCreateTable, ExcelUtils.getTableFields(datasourceRequest)); } catch (Exception e) { - DEException.throwException("Failed to create table " + toCreateTable); + DEException.throwException("Failed to create table " + toCreateTable + ", " + e.getMessage()); } } datasourceSyncManage.extractExcelData(requestDatasource, "all_scope"); @@ -605,6 +612,31 @@ public class DatasourceServer implements DatasourceApi { return validate(coreDatasource); } + public void addJob(List sysSettings) { + String type = "minute"; + String interval = "30"; + for (CoreSysSetting sysSetting : sysSettings) { + if (sysSetting.getPkey().equalsIgnoreCase("basic.dsExecuteTime")) { + type = sysSetting.getPval(); + } + if (sysSetting.getPkey().equalsIgnoreCase("basic.dsIntervalTime")) { + interval = sysSetting.getPval(); + } + } + String cron = ""; + switch (type) { + case "hour": + cron = "0 0 0/hour * * ? *".replace("hour", interval.toString()); + break; + default: + cron = "0 0/minute * * * ? *".replace("minute", interval.toString()); + } + scheduleManager.addOrUpdateCronJob(new JobKey("Datasource", "check_status"), + new TriggerKey("Datasource", "check_status"), + CheckDsStatusJob.class, + cron, new Date(System.currentTimeMillis()), null, new JobDataMap()); + } + private DatasourceDTO validate(CoreDatasource coreDatasource) { checkDatasourceStatus(coreDatasource); DatasourceDTO datasourceDTO = new DatasourceDTO(); diff --git a/core/core-backend/src/main/java/io/dataease/job/sechedule/CheckDsStatusJob.java b/core/core-backend/src/main/java/io/dataease/job/sechedule/CheckDsStatusJob.java new file mode 100644 index 0000000000..71c63b3b70 --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/job/sechedule/CheckDsStatusJob.java @@ -0,0 +1,27 @@ +package io.dataease.job.sechedule; + + +import io.dataease.datasource.server.DatasourceServer; +import io.dataease.utils.CommonBeanFactory; +import io.dataease.utils.LogUtil; +import jakarta.annotation.Resource; +import org.quartz.*; +import org.springframework.stereotype.Component; + +@Component +public class CheckDsStatusJob implements Job { + + @Resource + private DatasourceServer datasourceServer; + + public CheckDsStatusJob() { + datasourceServer = (DatasourceServer) CommonBeanFactory.getBean(DatasourceServer.class); + } + + @Override + public void execute(JobExecutionContext context) throws JobExecutionException { + LogUtil.info("Begin to check ds status..."); + datasourceServer.updateDatasourceStatus(); + } + +} diff --git a/core/core-backend/src/main/java/io/dataease/job/sechedule/Schedular.java b/core/core-backend/src/main/java/io/dataease/job/sechedule/Schedular.java index 4acfab638c..cb42755571 100644 --- a/core/core-backend/src/main/java/io/dataease/job/sechedule/Schedular.java +++ b/core/core-backend/src/main/java/io/dataease/job/sechedule/Schedular.java @@ -18,9 +18,4 @@ public class Schedular { datasourceServer.updateStopJobStatus(); } - @QuartzScheduled(cron = "0 0/30 * * * ?") - public void updateDatasourceStatus() { - datasourceServer.updateDatasourceStatus(); - } - } diff --git a/core/core-backend/src/main/java/io/dataease/license/server/LicenseServer.java b/core/core-backend/src/main/java/io/dataease/license/server/LicenseServer.java index a268317e8e..69978d0abe 100644 --- a/core/core-backend/src/main/java/io/dataease/license/server/LicenseServer.java +++ b/core/core-backend/src/main/java/io/dataease/license/server/LicenseServer.java @@ -14,7 +14,7 @@ import org.springframework.web.bind.annotation.RestController; @RequestMapping("/license") public class LicenseServer implements LicenseApi { - private static final String product = "DataEase"; + private static final String product = "DataEase v2"; @Resource private CoreLicManage coreLicManage; diff --git a/core/core-backend/src/main/java/io/dataease/listener/DataSourceInitStartListener.java b/core/core-backend/src/main/java/io/dataease/listener/DataSourceInitStartListener.java index 72dbae8e67..ec8324d30d 100644 --- a/core/core-backend/src/main/java/io/dataease/listener/DataSourceInitStartListener.java +++ b/core/core-backend/src/main/java/io/dataease/listener/DataSourceInitStartListener.java @@ -6,6 +6,8 @@ import io.dataease.datasource.provider.CalciteProvider; import io.dataease.datasource.server.DatasourceServer; import io.dataease.datasource.server.DatasourceTaskServer; import io.dataease.datasource.server.EngineServer; +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.boot.context.event.ApplicationReadyEvent; @@ -29,6 +31,8 @@ public class DataSourceInitStartListener implements ApplicationListener coreSysSettings = sysParameterManage.groupList("basic."); + datasourceServer.addJob(coreSysSettings); + }catch (Exception e){ + e.printStackTrace(); + } + } diff --git a/core/core-backend/src/main/java/io/dataease/system/manage/SysParameterManage.java b/core/core-backend/src/main/java/io/dataease/system/manage/SysParameterManage.java index 4f9d477557..063757433e 100644 --- a/core/core-backend/src/main/java/io/dataease/system/manage/SysParameterManage.java +++ b/core/core-backend/src/main/java/io/dataease/system/manage/SysParameterManage.java @@ -2,6 +2,7 @@ package io.dataease.system.manage; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import io.dataease.api.system.vo.SettingItemVO; +import io.dataease.datasource.server.DatasourceServer; import io.dataease.license.config.XpackInteract; import io.dataease.system.dao.auto.entity.CoreSysSetting; import io.dataease.system.dao.auto.mapper.CoreSysSettingMapper; @@ -31,6 +32,8 @@ public class SysParameterManage { @Resource private ExtCoreSysSettingMapper extCoreSysSettingMapper; + @Resource + private DatasourceServer datasourceServer; public String singleVal(String key) { QueryWrapper queryWrapper = new QueryWrapper<>(); @@ -100,6 +103,7 @@ public class SysParameterManage { return sysSetting; }).collect(Collectors.toList()); extCoreSysSettingMapper.saveBatch(sysSettings); + datasourceServer.addJob(sysSettings); } 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 451e4c08d6..f446ff2c24 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 @@ -7,7 +7,7 @@ import io.dataease.api.template.dto.TemplateMarketPreviewInfoDTO; import io.dataease.api.template.response.*; import io.dataease.api.template.vo.MarketApplicationSpecVO; import io.dataease.api.template.vo.MarketMetaDataVO; -import io.dataease.api.template.vo.TemplateCategoryVO; +import io.dataease.constant.CommonConstants; import io.dataease.exception.DEException; import io.dataease.operation.manage.CoreOptRecentManage; import io.dataease.system.manage.SysParameterManage; @@ -17,11 +17,11 @@ import io.dataease.utils.HttpClientUtil; import io.dataease.utils.JsonUtil; import io.dataease.utils.LogUtil; import jakarta.annotation.Resource; -import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; import java.util.*; +import java.util.function.Function; import java.util.stream.Collectors; /** @@ -29,14 +29,8 @@ import java.util.stream.Collectors; */ @Service public class TemplateCenterManage { - - private final static String POSTS_API = "/api/content/posts?page=0&size=2000"; - private final static String POSTS_API_V2 = "/apis/api.store.halo.run/v1alpha1/applications?keyword=&priceMode=&sort=latestReleaseTimestamp%2Cdesc&type=THEME&deVersion=V2&templateType=&label=&page=1&size=2000"; - private final static String CATEGORIES_API = "/api/content/categories"; - private final static String TEMPLATE_META_DATA_URL = "/upload/meta_data.json"; - @Resource private SysParameterManage sysParameterManage; @@ -71,9 +65,14 @@ public class TemplateCenterManage { } private MarketTemplateV2BaseResponse templateQuery(Map templateParams) { - String result = marketGet(templateParams.get("template.url") + POSTS_API_V2, null); - MarketTemplateV2BaseResponse postsResult = JsonUtil.parseObject(result, MarketTemplateV2BaseResponse.class); - return postsResult; + try { + String result = marketGet(templateParams.get("template.url") + POSTS_API_V2, null); + MarketTemplateV2BaseResponse postsResult = JsonUtil.parseObject(result, MarketTemplateV2BaseResponse.class); + return postsResult; + } catch (Exception e) { + LogUtil.error(e); + return null; + } } public MarketBaseResponse searchTemplate() { @@ -81,7 +80,8 @@ public class TemplateCenterManage { Map templateParams = sysParameterManage.groupVal("template."); return baseResponseV2Trans(templateQuery(templateParams), searchTemplateFromManage(), templateParams.get("template.url")); } catch (Exception e) { - DEException.throwException(e); + LogUtil.error(e); + e.printStackTrace(); } return null; } @@ -121,69 +121,77 @@ public class TemplateCenterManage { public MarketPreviewBaseResponse searchTemplatePreview() { try { - Map templateParams = sysParameterManage.groupVal("template."); - return basePreviewResponseV2Trans(templateQuery(templateParams), searchTemplateFromManage(), templateParams.get("template.url")); + MarketBaseResponse baseContentRsp = searchTemplate(); + List categories = baseContentRsp.getCategories().stream().filter(category -> !"最近使用".equals(category.getLabel())).collect(Collectors.toList()); + List contents = baseContentRsp.getContents(); + List previewContents = new ArrayList<>(); + categories.forEach(category -> { + if ("推荐".equals(category.getLabel())) { + previewContents.add(new TemplateMarketPreviewInfoDTO(category, contents.stream().filter(template -> "Y".equals(template.getSuggest())).collect(Collectors.toList()))); + } else { + previewContents.add(new TemplateMarketPreviewInfoDTO(category, contents.stream().filter(template -> checkCategoryMatch(template, category.getLabel())).collect(Collectors.toList()))); + } + }); + return new MarketPreviewBaseResponse(baseContentRsp.getBaseUrl(), categories.stream().map(MarketMetaDataVO::getLabel) + .collect(Collectors.toList()), previewContents); } catch (Exception e) { - DEException.throwException(e); + LogUtil.error(e); } return null; } + private Boolean checkCategoryMatch(TemplateMarketDTO template, String categoryNameMatch) { + try { + return template.getCategories().stream() + .anyMatch(category -> categoryNameMatch.equals(category.getName())); + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + private MarketBaseResponse baseResponseV2TransRecommend(MarketTemplateV2BaseResponse v2BaseResponse, String url) { Map useTime = coreOptRecentManage.findTemplateRecentUseTime(); - Map categoriesMap = getCategoriesBaseV2(); + List categoryVO = getCategoriesV2().stream().filter(node -> !"全部".equalsIgnoreCase(node.getLabel())).collect(Collectors.toList()); + Map categoriesMap = categoryVO.stream() + .collect(Collectors.toMap(MarketMetaDataVO::getSlug, MarketMetaDataVO::getLabel)); List contents = new ArrayList<>(); - v2BaseResponse.getItems().stream().forEach(marketTemplateV2ItemResult -> { - MarketApplicationSpecVO spec = marketTemplateV2ItemResult.getApplication().getSpec(); - if ("Y".equalsIgnoreCase(spec.getSuggest())) { - contents.add(new TemplateMarketDTO(spec.getReadmeName(), spec.getDisplayName(), spec.getScreenshots().get(0).getUrl(), spec.getLinks().get(0).getUrl(), categoriesMap.get(spec.getLabel()), spec.getTemplateType(), useTime.get(spec.getReadmeName()), "Y")); - } - }); + if (v2BaseResponse != null) { + v2BaseResponse.getItems().stream().forEach(marketTemplateV2ItemResult -> { + MarketApplicationSpecVO spec = marketTemplateV2ItemResult.getApplication().getSpec(); + if ("Y".equalsIgnoreCase(spec.getSuggest())) { + contents.add(new TemplateMarketDTO(spec.getReadmeName(), spec.getDisplayName(), spec.getScreenshots().get(0).getUrl(), spec.getLinks().get(0).getUrl(), categoriesMap.get(spec.getLabel()), spec.getTemplateType(), useTime.get(spec.getReadmeName()), "Y")); + } + }); + } // 最近使用排序 Collections.sort(contents); - return new MarketBaseResponse(url, contents); + return new MarketBaseResponse(url, categoryVO, contents); } private MarketBaseResponse baseResponseV2Trans(MarketTemplateV2BaseResponse v2BaseResponse, List contents, String url) { Map useTime = coreOptRecentManage.findTemplateRecentUseTime(); - Map categoriesMap = getCategoriesBaseV2(); - v2BaseResponse.getItems().stream().forEach(marketTemplateV2ItemResult -> { - MarketApplicationSpecVO spec = marketTemplateV2ItemResult.getApplication().getSpec(); - contents.add(new TemplateMarketDTO(spec.getReadmeName(), spec.getDisplayName(), spec.getScreenshots().get(0).getUrl(), spec.getLinks().get(0).getUrl(), categoriesMap.get(spec.getLabel()), spec.getTemplateType(), useTime.get(spec.getReadmeName()), spec.getSuggest())); + List categoryVO = getCategoriesObject().stream().filter(node -> !"全部".equalsIgnoreCase(node.getLabel())).collect(Collectors.toList()); + Map categoriesMap = categoryVO.stream() + .collect(Collectors.toMap(MarketMetaDataVO::getValue, MarketMetaDataVO::getLabel)); + List activeCategoriesName = new ArrayList<>(Arrays.asList("最近使用", "推荐")); + contents.stream().forEach(templateMarketDTO -> { + Long recentUseTime = useTime.get(templateMarketDTO.getId()); + templateMarketDTO.setRecentUseTime(recentUseTime == null ? 0 : recentUseTime); + activeCategoriesName.add(templateMarketDTO.getMainCategory()); }); + if (v2BaseResponse != null) { + v2BaseResponse.getItems().stream().forEach(marketTemplateV2ItemResult -> { + MarketApplicationSpecVO spec = marketTemplateV2ItemResult.getApplication().getSpec(); + contents.add(new TemplateMarketDTO(spec.getReadmeName(), spec.getDisplayName(), spec.getScreenshots().get(0).getUrl(), spec.getLinks().get(0).getUrl(), categoriesMap.get(spec.getLabel()), spec.getTemplateType(), useTime.get(spec.getReadmeName()), spec.getSuggest())); + if (categoriesMap.get(spec.getLabel()) != null) { + activeCategoriesName.add(categoriesMap.get(spec.getLabel())); + } + }); + } // 最近使用排序 Collections.sort(contents); - return new MarketBaseResponse(url, contents); - } - - private MarketPreviewBaseResponse basePreviewResponseV2Trans(MarketTemplateV2BaseResponse v2BaseResponse, List manageContents, String url) { - Map useTime = coreOptRecentManage.findTemplateRecentUseTime(); - List categoryVO = getCategoriesV2(); - Map categoriesMap = categoryVO.stream() - .collect(Collectors.toMap(MarketMetaDataVO::getSlug, MarketMetaDataVO::getLabel)); - List categories = categoryVO.stream().filter(node -> !"全部".equalsIgnoreCase(node.getLabel())).map(MarketMetaDataVO::getLabel) - .collect(Collectors.toList()); - List result = new ArrayList<>(); - categoriesMap.forEach((key, value) -> { - if (!"全部".equalsIgnoreCase(value)) { - List contents = new ArrayList<>(); - v2BaseResponse.getItems().stream().forEach(marketTemplateV2ItemResult -> { - MarketApplicationSpecVO spec = marketTemplateV2ItemResult.getApplication().getSpec(); - if (key.equalsIgnoreCase(spec.getLabel())) { - contents.add(new TemplateMarketDTO(spec.getReadmeName(), spec.getDisplayName(), spec.getScreenshots().get(0).getUrl(), spec.getLinks().get(0).getUrl(), categoriesMap.get(spec.getLabel()), spec.getTemplateType(), useTime.get(spec.getReadmeName()), spec.getSuggest())); - } - }); - manageContents.stream().forEach(templateMarketDTO -> { - if (value.equalsIgnoreCase(templateMarketDTO.getMainCategory())) { - contents.add(templateMarketDTO); - } - }); - Collections.sort(contents); - result.add(new TemplateMarketPreviewInfoDTO(value, contents)); - } - }); - // 最近使用排序 - return new MarketPreviewBaseResponse(url, categories, result); + return new MarketBaseResponse(url, categoryVO.stream().filter(node -> activeCategoriesName.contains(node.getLabel())).collect(Collectors.toList()), contents); } @@ -194,8 +202,7 @@ public class TemplateCenterManage { public List getCategoriesObject() { List result = getCategoriesV2(); - result.add(0, new MarketMetaDataVO("suggest", "推荐")); - result.add(0, new MarketMetaDataVO("recent", "最近使用")); + result.add(0, new MarketMetaDataVO("recent", "最近使用", CommonConstants.TEMPLATE_SOURCE.PUBLIC)); return result; } @@ -209,18 +216,35 @@ public class TemplateCenterManage { List allCategories = new ArrayList<>(); List manageCategories = templateManageMapper.findBaseTemplateList("folder"); List manageCategoriesTrans = manageCategories.stream() - .map(templateCategory -> new MarketMetaDataVO(templateCategory.getId(), templateCategory.getName())) + .map(templateCategory -> new MarketMetaDataVO(templateCategory.getId(), templateCategory.getName(), CommonConstants.TEMPLATE_SOURCE.MANAGE)) .collect(Collectors.toList()); try { Map templateParams = sysParameterManage.groupVal("template."); String resultStr = marketGet(templateParams.get("template.url") + TEMPLATE_META_DATA_URL, null); MarketMetaDataBaseResponse metaData = JsonUtil.parseObject(resultStr, MarketMetaDataBaseResponse.class); allCategories.addAll(metaData.getLabels()); + allCategories.add(0, new MarketMetaDataVO("suggest", "推荐", CommonConstants.TEMPLATE_SOURCE.PUBLIC)); } catch (Exception e) { LogUtil.error("模板市场分类获取错误", e); } - allCategories.addAll(manageCategoriesTrans); - return allCategories; + + return mergeAndDistinctByLabel(allCategories, manageCategoriesTrans); } + + private List mergeAndDistinctByLabel(List list1, List list2) { + List mergedList = new ArrayList<>(list1); + mergedList.addAll(list2); + Map marketMetaDataMap = mergedList.stream() + .collect(Collectors.toMap( + MarketMetaDataVO::getLabel, + Function.identity(), + (existing, replacement) -> { + existing.setSource(CommonConstants.TEMPLATE_SOURCE.PUBLIC); + return existing; + }, + LinkedHashMap::new + )); + return new ArrayList<>(marketMetaDataMap.values()); + } } 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 188a83c7d4..ba43f7c297 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 @@ -242,6 +242,8 @@ public class DataVisualizationServer implements DataVisualizationApi { dynamicData = visualizationTemplate.getDynamicData(); name = visualizationTemplate.getName(); dvType = visualizationTemplate.getDvType(); + // 模板市场记录 + coreOptRecentManage.saveOpt(request.getTemplateId(), OptConstants.OPT_RESOURCE_TYPE.TEMPLATE,OptConstants.OPT_TYPE.NEW); } else if (DataVisualizationConstants.NEW_PANEL_FROM.NEW_OUTER_TEMPLATE.equals(newFrom)) { templateStyle = request.getCanvasStyleData(); templateData = request.getComponentData(); diff --git a/core/core-backend/src/main/resources/application-standalone.yml b/core/core-backend/src/main/resources/application-standalone.yml index 44c824b268..a179fd34d0 100644 --- a/core/core-backend/src/main/resources/application-standalone.yml +++ b/core/core-backend/src/main/resources/application-standalone.yml @@ -4,7 +4,7 @@ spring: username: root password: 123456 messages: - basename: i18n/core,i18n/permissions + basename: i18n/lic,i18n/core,i18n/permissions flyway: enabled: true table: de_standalone_version 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 94fd98f6ff..7407153084 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 @@ -36,4 +36,7 @@ CREATE TABLE `visualization_template_extend_data` ( ALTER TABLE `core_opt_recent` MODIFY COLUMN `resource_id` bigint NULL COMMENT '资源ID' AFTER `id`, - ADD COLUMN `resource_name` varchar(255) NULL COMMENT '资源名称' AFTER `resource_id`; \ No newline at end of file + ADD COLUMN `resource_name` varchar(255) NULL COMMENT '资源名称' AFTER `resource_id`; + +INSERT INTO `core_sys_setting` (`id`, `pkey`, `pval`, `type`, `sort`) VALUES (7, 'template.url', 'https://templates-de.fit2cloud.com', 'text', 0); +INSERT INTO `core_sys_setting` (`id`, `pkey`, `pval`, `type`, `sort`) VALUES (8, 'template.accessKey', 'dataease', 'text', 1); diff --git a/core/core-backend/src/main/resources/db/migration/V2.1__ddl.sql b/core/core-backend/src/main/resources/db/migration/V2.1__ddl.sql index cf35e2b70f..5567701ebf 100644 --- a/core/core-backend/src/main/resources/db/migration/V2.1__ddl.sql +++ b/core/core-backend/src/main/resources/db/migration/V2.1__ddl.sql @@ -22,7 +22,9 @@ BEGIN; INSERT INTO `core_menu` VALUES (19, 0, 2, 'template-market', 'template-market', 4, NULL, '/template-market', 1, 1, 0); INSERT INTO `core_menu` -VALUES (20, 15, 2, 'template-setting', 'system/template-setting', 4, 'icon_template', '/template-setting', 0, 1, 1); +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); COMMIT; DROP TABLE IF EXISTS `visualization_template_extend_data`; @@ -52,6 +54,10 @@ CREATE TABLE `core_area_custom` ); BEGIN; -INSERT INTO `core_sys_setting` VALUES (1, 'basic.dsIntervalTime', '6', 'text', 2); -INSERT INTO `core_sys_setting` VALUES (2, 'basic.dsExecuteTime', 'minute', 'text', 3); +INSERT INTO `core_sys_setting` +VALUES (1, 'basic.dsIntervalTime', '6', 'text', 2); +INSERT INTO `core_sys_setting` +VALUES (2, 'basic.dsExecuteTime', 'minute', 'text', 3); +INSERT INTO `core_sys_setting` (`id`, `pkey`, `pval`, `type`, `sort`) VALUES (7, 'template.url', 'https://templates-de.fit2cloud.com', 'text', 0); +INSERT INTO `core_sys_setting` (`id`, `pkey`, `pval`, `type`, `sort`) VALUES (8, 'template.accessKey', 'dataease', 'text', 1); COMMIT; diff --git a/core/core-backend/src/main/resources/ehcache/ehcache.xml b/core/core-backend/src/main/resources/ehcache/ehcache.xml index e1ebb242a0..27b2096ef5 100644 --- a/core/core-backend/src/main/resources/ehcache/ehcache.xml +++ b/core/core-backend/src/main/resources/ehcache/ehcache.xml @@ -83,6 +83,11 @@ java.lang.Integer + + java.lang.String + java.util.List + + java.lang.String java.util.List @@ -130,17 +135,17 @@ - + java.lang.String java.util.List - + diff --git a/core/core-frontend/config/base.ts b/core/core-frontend/config/base.ts index 61513f83d1..ddb203e13c 100644 --- a/core/core-frontend/config/base.ts +++ b/core/core-frontend/config/base.ts @@ -26,6 +26,6 @@ export default { } } }, - sourcemap: false + sourcemap: true } } diff --git a/core/core-frontend/pom.xml b/core/core-frontend/pom.xml index ad838cb91a..fefb99318b 100644 --- a/core/core-frontend/pom.xml +++ b/core/core-frontend/pom.xml @@ -5,7 +5,7 @@ core io.dataease - 2.0.0 + 2.1.0 4.0.0 @@ -21,7 +21,7 @@ - + com.github.eirslett frontend-maven-plugin ${frontend-maven-plugin.version} - + + + + npm run build diff --git a/core/core-frontend/src/config/axios/service.ts b/core/core-frontend/src/config/axios/service.ts index c066786dd7..944bdc38e1 100644 --- a/core/core-frontend/src/config/axios/service.ts +++ b/core/core-frontend/src/config/axios/service.ts @@ -116,10 +116,10 @@ service.interceptors.response.use( response: AxiosResponse & { config: InternalAxiosRequestConfig & { loading?: boolean } } ) => { executeVersionHandler(response) - if (response.headers['x-de-refresh-token']) { + /* if (response.headers['x-de-refresh-token']) { wsCache.set('user.token', response.headers['x-de-refresh-token']) wsCache.set('user.exp', new Date().getTime() + 90000) - } + } */ if (response.headers['x-de-link-token']) { linkStore.setLinkToken(response.headers['x-de-link-token']) } diff --git a/core/core-frontend/src/layout/components/Header.vue b/core/core-frontend/src/layout/components/Header.vue index 56e532ef47..3a419061dc 100644 --- a/core/core-frontend/src/layout/components/Header.vue +++ b/core/core-frontend/src/layout/components/Header.vue @@ -7,6 +7,7 @@ import HeaderMenuItem from './HeaderMenuItem.vue' import { Icon } from '@/components/icon-custom' import { ElHeader, ElMenu } from 'element-plus-secondary' import SystemCfg from './SystemCfg.vue' +import ToolboxCfg from './ToolboxCfg.vue' import { useRouter, useRoute } from 'vue-router' import TopDoc from '@/layout/components/TopDoc.vue' import AccountOperator from '@/layout/components/AccountOperator.vue' @@ -26,6 +27,7 @@ const permissionStore = usePermissionStore() const routers: any[] = formatRoute(permissionStore.getRoutersNotHidden as AppCustomRouteRecordRaw[]) const showSystem = ref(false) +const showToolbox = ref(false) const handleSelect = (index: string) => { // 自定义事件 if (isExternal(index)) { @@ -37,8 +39,12 @@ const handleSelect = (index: string) => { const initShowSystem = () => { showSystem.value = permissionStore.getRouters.some(route => route.path === '/system') } +const initShowToolbox = () => { + showToolbox.value = permissionStore.getRouters.some(route => route.path === '/toolbox') +} onMounted(() => { initShowSystem() + initShowToolbox() }) @@ -56,6 +62,7 @@ onMounted(() => {
+ diff --git a/core/core-frontend/src/layout/components/HeaderSystem.vue b/core/core-frontend/src/layout/components/HeaderSystem.vue index b86df484b2..1a835b0d76 100644 --- a/core/core-frontend/src/layout/components/HeaderSystem.vue +++ b/core/core-frontend/src/layout/components/HeaderSystem.vue @@ -2,7 +2,11 @@ import { ElHeader } from 'element-plus-secondary' import { useRouter } from 'vue-router' import AccountOperator from '@/layout/components/AccountOperator.vue' +import { propTypes } from '@/utils/propTypes' const { push } = useRouter() +const props = defineProps({ + title: propTypes.string.def('系统设置') +}) const backToMain = () => { push('/workbranch/index') } @@ -12,7 +16,7 @@ const backToMain = () => { - 系统设置 + {{ props.title || '系统设置' }}
diff --git a/core/core-frontend/src/layout/components/ToolboxCfg.vue b/core/core-frontend/src/layout/components/ToolboxCfg.vue new file mode 100644 index 0000000000..35635621cf --- /dev/null +++ b/core/core-frontend/src/layout/components/ToolboxCfg.vue @@ -0,0 +1,34 @@ + + + + + diff --git a/core/core-frontend/src/layout/index.vue b/core/core-frontend/src/layout/index.vue index 53fa889f56..9ef95a5ea1 100644 --- a/core/core-frontend/src/layout/index.vue +++ b/core/core-frontend/src/layout/index.vue @@ -7,23 +7,28 @@ import Menu from './components/Menu.vue' import Main from './components/Main.vue' import { ElContainer } from 'element-plus-secondary' import { useRoute } from 'vue-router' -import HeaderTemplateMarket from '@/layout/components/HeaderTemplateMarket.vue' const route = useRoute() const systemMenu = computed(() => route.path.includes('system')) const settingMenu = computed(() => route.path.includes('sys-setting')) -const templateMarketMenu = computed(() => route.path.includes('template-market')) +const marketMenu = computed(() => route.path.includes('template-market')) +const toolboxMenu = computed(() => route.path.includes('toolbox')) diff --git a/core/core-frontend/src/views/about/index.vue b/core/core-frontend/src/views/about/index.vue index 3fd3c4b07e..a837d29507 100644 --- a/core/core-frontend/src/views/about/index.vue +++ b/core/core-frontend/src/views/about/index.vue @@ -90,7 +90,7 @@ const validateHandler = (param, success) => { } const getLicense = result => { if (result.status === 'valid') { - tipsSuffix.value = result.edition === 'Embedded' ? '套' : '个账号' + tipsSuffix.value = result?.license?.edition === 'Embedded' ? '套' : '个账号' } return { status: result.status, diff --git a/core/core-frontend/src/views/chart/components/js/panel/charts/line/area.ts b/core/core-frontend/src/views/chart/components/js/panel/charts/line/area.ts index 4b2b6b3181..777e024bfe 100644 --- a/core/core-frontend/src/views/chart/components/js/panel/charts/line/area.ts +++ b/core/core-frontend/src/views/chart/components/js/panel/charts/line/area.ts @@ -176,8 +176,16 @@ export class Area extends G2PlotChartView { const areaColors = [...colors, ...colors] let areaStyle if (customAttr.basicStyle.gradient) { - areaStyle = () => { - const ele = areaColors.shift() + const colorMap = new Map() + areaStyle = item => { + let ele + const key = `${item.field}-${item.category}` + if (colorMap.has(key)) { + ele = colorMap.get(key) + } else { + ele = areaColors.shift() + colorMap.set(key, ele) + } if (ele) { return { fill: setGradientColor(hexColorToRGBA(ele, alpha), true, 270) diff --git a/core/core-frontend/src/views/common/DeResourceTree.vue b/core/core-frontend/src/views/common/DeResourceTree.vue index 2c42687aad..c77beb8d63 100644 --- a/core/core-frontend/src/views/common/DeResourceTree.vue +++ b/core/core-frontend/src/views/common/DeResourceTree.vue @@ -450,17 +450,17 @@ defineExpose({ @finish="resourceOptFinish" ref="resourceGroupOpt" /> - - - + - + + +
diff --git a/core/core-frontend/src/views/system/common/InfoTemplate.vue b/core/core-frontend/src/views/system/common/InfoTemplate.vue index 4dc05b29de..0d8eeb3dce 100644 --- a/core/core-frontend/src/views/system/common/InfoTemplate.vue +++ b/core/core-frontend/src/views/system/common/InfoTemplate.vue @@ -1,6 +1,6 @@