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 3c217a76b0..9c3dd007e8 100644 --- a/core/core-backend/src/main/java/io/dataease/MybatisPlusGenerator.java +++ b/core/core-backend/src/main/java/io/dataease/MybatisPlusGenerator.java @@ -14,7 +14,7 @@ public class MybatisPlusGenerator { * 第一 我嫌麻烦 * 第二 后面配置会放到nacos读起来更麻烦了 */ - private static final String url = "jdbc:mysql://39.98.78.97:3306/dataease?autoReconnect=false&useUnicode=true&characterEncoding=UTF-8&characterSetResults=UTF-8&zeroDateTimeBehavior=convertToNull&useSSL=false"; + private static final String url = "jdbc:mysql://127.0.0.1:3306/de_standalone?autoReconnect=false&useUnicode=true&characterEncoding=UTF-8&characterSetResults=UTF-8&zeroDateTimeBehavior=convertToNull&useSSL=false"; private static final String username = "root"; private static final String password = "Password123@mysql"; @@ -25,7 +25,7 @@ public class MybatisPlusGenerator { /** * 这是要生成代码的表名称 */ - private static final String TABLE_NAME = "visualization_template"; + private static final String TABLE_NAME = "visualization_template_extend_data"; /** * 下面两个配置基本上不用动 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 2462a2a849..25acbfd475 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 @@ -1,6 +1,24 @@ package io.dataease.commons.constants; public class DataVisualizationConstants { + + //新建仪表板来源 + public static final class NEW_PANEL_FROM { + + // 直接新建 + public static final String NEW = "new"; + + // 内部模板新建 + public static final String NEW_INNER_TEMPLATE = "new_inner_template"; + + // 外部模板新建 + public static final String NEW_OUTER_TEMPLATE = "new_outer_template"; + + // 模板市场新建 + public static final String NEW_MARKET_TEMPLATE = "new_market_template"; + + } + //删除标志 public static final class DELETE_FLAG { //已删除 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 636342e8fd..48bbbada2f 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 @@ -7,8 +7,12 @@ import io.dataease.utils.IDUtils; import jakarta.annotation.Resource; import org.apache.commons.lang3.ObjectUtils; import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import java.util.Collection; import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; @Component public class SysParameterManage { @@ -57,4 +61,14 @@ public class SysParameterManage { QueryWrapper queryWrapper = new QueryWrapper<>(); return coreSysSettingMapper.selectList(queryWrapper); } + + public Map groupVal(String groupKey) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.likeLeft("pkey", groupKey); + List sysSettings = coreSysSettingMapper.selectList(queryWrapper); + if (!CollectionUtils.isEmpty(sysSettings)) { + return sysSettings.stream().collect(Collectors.toMap(CoreSysSetting::getPkey, CoreSysSetting::getPval)); + } + return null; + } } diff --git a/core/core-backend/src/main/java/io/dataease/template/dao/auto/entity/VisualizationTemplateExtendData.java b/core/core-backend/src/main/java/io/dataease/template/dao/auto/entity/VisualizationTemplateExtendData.java new file mode 100644 index 0000000000..6c25244e0e --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/template/dao/auto/entity/VisualizationTemplateExtendData.java @@ -0,0 +1,90 @@ +package io.dataease.template.dao.auto.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import java.io.Serializable; + +/** + *

+ * + *

+ * + * @author fit2cloud + * @since 2023-11-10 + */ +@TableName("visualization_template_extend_data") +public class VisualizationTemplateExtendData implements Serializable { + + private static final long serialVersionUID = 1L; + + private Long id; + + private Long dvId; + + private Long viewId; + + private String viewDetails; + + private String copyFrom; + + private String copyId; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getDvId() { + return dvId; + } + + public void setDvId(Long dvId) { + this.dvId = dvId; + } + + public Long getViewId() { + return viewId; + } + + public void setViewId(Long viewId) { + this.viewId = viewId; + } + + public String getViewDetails() { + return viewDetails; + } + + public void setViewDetails(String viewDetails) { + this.viewDetails = viewDetails; + } + + public String getCopyFrom() { + return copyFrom; + } + + public void setCopyFrom(String copyFrom) { + this.copyFrom = copyFrom; + } + + public String getCopyId() { + return copyId; + } + + public void setCopyId(String copyId) { + this.copyId = copyId; + } + + @Override + public String toString() { + return "VisualizationTemplateExtendData{" + + "id = " + id + + ", dvId = " + dvId + + ", viewId = " + viewId + + ", viewDetails = " + viewDetails + + ", copyFrom = " + copyFrom + + ", copyId = " + copyId + + "}"; + } +} diff --git a/core/core-backend/src/main/java/io/dataease/template/dao/auto/mapper/VisualizationTemplateExtendDataMapper.java b/core/core-backend/src/main/java/io/dataease/template/dao/auto/mapper/VisualizationTemplateExtendDataMapper.java new file mode 100644 index 0000000000..ee5d10116c --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/template/dao/auto/mapper/VisualizationTemplateExtendDataMapper.java @@ -0,0 +1,18 @@ +package io.dataease.template.dao.auto.mapper; + +import io.dataease.template.dao.auto.entity.VisualizationTemplateExtendData; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; + +/** + *

+ * Mapper 接口 + *

+ * + * @author fit2cloud + * @since 2023-11-10 + */ +@Mapper +public interface VisualizationTemplateExtendDataMapper extends BaseMapper { + +} diff --git a/core/core-backend/src/main/java/io/dataease/template/manage/TemplateMarketManage.java b/core/core-backend/src/main/java/io/dataease/template/manage/TemplateMarketManage.java new file mode 100644 index 0000000000..e780399556 --- /dev/null +++ b/core/core-backend/src/main/java/io/dataease/template/manage/TemplateMarketManage.java @@ -0,0 +1,87 @@ +package io.dataease.template.manage; + +import com.fasterxml.jackson.core.type.TypeReference; +import io.dataease.api.template.dto.TemplateManageFileDTO; +import io.dataease.api.template.dto.TemplateMarketDTO; +import io.dataease.api.template.request.TemplateMarketSearchRequest; +import io.dataease.api.template.response.MarketBaseResponse; +import io.dataease.api.template.vo.TemplateCategoryVO; +import io.dataease.exception.DEException; +import io.dataease.system.manage.SysParameterManage; +import io.dataease.utils.HttpClientConfig; +import io.dataease.utils.HttpClientUtil; +import io.dataease.utils.JsonUtil; +import jakarta.annotation.Resource; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * Author: wangjiahao + */ +@Service +public class TemplateMarketManage { + + private final static String POSTS_API = "/api/content/posts?page=0&size=2000"; + private final static String CATEGORIES_API = "/api/content/categories"; + + @Resource + private SysParameterManage sysParameterManage; + + /** + * @param templateUrl template url + * @Description Get template file from template market + */ + public TemplateManageFileDTO getTemplateFromMarket(String templateUrl) { + if (StringUtils.isNotEmpty(templateUrl)) { + String sufUrl = sysParameterManage.groupVal("template.").get("template.url"); + String templateInfo = HttpClientUtil.get(sufUrl + templateUrl, null); + return JsonUtil.parseObject(templateInfo,TemplateManageFileDTO.class); + } else { + return null; + } + } + + /** + * @param url content api url + * @Description Get info from template market content api + */ + public String marketGet(String url, String accessKey) { + HttpClientConfig config = new HttpClientConfig(); + config.addHeader("API-Authorization", accessKey); + return HttpClientUtil.get(url, config); + } + + public MarketBaseResponse searchTemplate(TemplateMarketSearchRequest request) { + try { + Map templateParams = sysParameterManage.groupVal("template."); + String result = marketGet(templateParams.get("template.url") + POSTS_API, templateParams.get("template.accessKey")); + TypeReference> market = new TypeReference<>() { + }; + List postsResult = JsonUtil.parseList(result,market); + return new MarketBaseResponse(templateParams.get("template.url"), postsResult); + } catch (Exception e) { + DEException.throwException(e); + } + return null; + } + + public List getCategories() { + Map templateParams = sysParameterManage.groupVal("template."); + String resultStr = marketGet(templateParams.get("template.url") + CATEGORIES_API, templateParams.get("template.accessKey")); + TypeReference> market = new TypeReference<>() { + }; + List categories = JsonUtil.parseList(resultStr,market); + if (CollectionUtils.isNotEmpty(categories)) { + return categories.stream().filter(item -> !"应用系列".equals(item.getName())).sorted(Comparator.comparing(TemplateCategoryVO::getPriority)).map(TemplateCategoryVO::getName).collect(Collectors.toList()); + } else { + return null; + } + + } +} diff --git a/core/core-backend/src/main/java/io/dataease/template/service/TemplateManageService.java b/core/core-backend/src/main/java/io/dataease/template/service/TemplateManageService.java index 52aea40e7a..9b1d81ace7 100644 --- a/core/core-backend/src/main/java/io/dataease/template/service/TemplateManageService.java +++ b/core/core-backend/src/main/java/io/dataease/template/service/TemplateManageService.java @@ -1,6 +1,7 @@ package io.dataease.template.service; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import io.dataease.api.template.TemplateManageApi; import io.dataease.api.template.dto.TemplateManageDTO; import io.dataease.api.template.request.TemplateManageRequest; import io.dataease.api.template.vo.VisualizationTemplateVO; @@ -17,6 +18,8 @@ import org.apache.commons.lang3.StringUtils; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; import java.util.List; import java.util.Optional; @@ -28,7 +31,9 @@ import static io.dataease.constant.StaticResourceConstants.UPLOAD_URL_PREFIX; * @author : WangJiaHao * @date : 2023/11/7 13:29 */ -public class TemplateManageService { +@RestController +@RequestMapping("/templateManage") +public class TemplateManageService implements TemplateManageApi { @Resource private VisualizationTemplateMapper templateMapper; @@ -37,6 +42,7 @@ public class TemplateManageService { @Resource private StaticResourceServer staticResourceServer; + @Override public List templateList(TemplateManageRequest request) { request.setWithBlobs("N"); List templateList = extTemplateMapper.findTemplateList(request); @@ -58,7 +64,9 @@ public class TemplateManageService { return extTemplateMapper.findTemplateList(request); } + @Transactional + @Override public TemplateManageDTO save(TemplateManageRequest request) { if (StringUtils.isEmpty(request.getId())) { request.setId(UUID.randomUUID().toString()); @@ -121,17 +129,17 @@ public class TemplateManageService { return CommonConstants.CHECK_RESULT.EXIST_ALL; } } - + @Override public String nameCheck(TemplateManageRequest request) { return nameCheck(request.getOptType(), request.getName(), request.getPid(), request.getId()); } - + @Override public void delete(String id) { Assert.notNull(id, "id cannot be null"); templateMapper.deleteById(id); } - + @Override public VisualizationTemplateVO findOne(String panelId) { VisualizationTemplate template = templateMapper.selectById(panelId); if(template != null){ @@ -142,7 +150,7 @@ public class TemplateManageService { return null; } } - + @Override public List find(TemplateManageRequest request) { return extTemplateMapper.findTemplateList(request); } 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 cf57e7a16d..8a73c7640d 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 @@ -3,22 +3,29 @@ package io.dataease.visualization.server; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import io.dataease.api.chart.dto.ChartViewDTO; +import io.dataease.api.template.dto.TemplateManageFileDTO; import io.dataease.api.visualization.DataVisualizationApi; import io.dataease.api.visualization.request.DataVisualizationBaseRequest; import io.dataease.api.visualization.request.VisualizationWorkbranchQueryRequest; import io.dataease.api.visualization.vo.DataVisualizationVO; import io.dataease.api.visualization.vo.VisualizationResourceVO; import io.dataease.chart.dao.auto.entity.CoreChartView; +import io.dataease.chart.dao.auto.mapper.CoreChartViewMapper; import io.dataease.chart.manage.ChartDataManage; import io.dataease.chart.manage.ChartViewManege; import io.dataease.commons.constants.DataVisualizationConstants; +import io.dataease.constant.CommonConstants; import io.dataease.exception.DEException; import io.dataease.license.config.XpackInteract; import io.dataease.model.BusiNodeRequest; import io.dataease.model.BusiNodeVO; +import io.dataease.template.dao.auto.entity.VisualizationTemplate; +import io.dataease.template.dao.auto.mapper.VisualizationTemplateMapper; +import io.dataease.template.manage.TemplateMarketManage; import io.dataease.utils.AuthUtils; import io.dataease.utils.BeanUtils; import io.dataease.utils.IDUtils; +import io.dataease.utils.JsonUtil; import io.dataease.visualization.dao.auto.entity.DataVisualizationInfo; import io.dataease.visualization.dao.auto.mapper.DataVisualizationInfoMapper; import io.dataease.visualization.dao.ext.mapper.ExtDataVisualizationMapper; @@ -29,7 +36,10 @@ 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.RestController; +import org.springframework.web.multipart.MultipartFile; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -54,6 +64,16 @@ public class DataVisualizationServer implements DataVisualizationApi { @Resource private ChartDataManage chartDataManage; + @Resource + private VisualizationTemplateMapper templateMapper; + + @Resource + private TemplateMarketManage templateMarketManage; + + @Resource + private StaticResourceServer staticResourceServer; + + @Override @XpackInteract(value = "dataVisualizationServer", original = true) public DataVisualizationVO findById(Long dvId,String busiFlag) { @@ -195,6 +215,74 @@ public class DataVisualizationServer implements DataVisualizationApi { return extDataVisualizationMapper.findDvType(dvId); } + @Override + public DataVisualizationVO decompression(DataVisualizationBaseRequest request) throws Exception { + Long newDvId = IDUtils.snowID(); + String newFrom = request.getNewFrom(); + String templateStyle = null; + String templateData = null; + String dynamicData = null; + String staticResource = null; + String name = null; + String dvType = null; + //内部模板新建 + if (DataVisualizationConstants.NEW_PANEL_FROM.NEW_INNER_TEMPLATE.equals(newFrom)) { + VisualizationTemplate visualizationTemplate = templateMapper.selectById(request.getTemplateId()); + templateStyle = visualizationTemplate.getTemplateStyle(); + templateData = visualizationTemplate.getTemplateData(); + dynamicData = visualizationTemplate.getDynamicData(); + name = visualizationTemplate.getName(); + dvType = visualizationTemplate.getDvType(); + } else if (DataVisualizationConstants.NEW_PANEL_FROM.NEW_OUTER_TEMPLATE.equals(newFrom)) { + templateStyle = request.getCanvasStyleData(); + templateData = request.getCanvasStyleData(); + dynamicData = request.getDynamicData(); + staticResource = request.getStaticResource(); + name = request.getName(); + dvType = request.getType(); + } else if (DataVisualizationConstants.NEW_PANEL_FROM.NEW_MARKET_TEMPLATE.equals(newFrom)) { + TemplateManageFileDTO templateFileInfo = templateMarketManage.getTemplateFromMarket(request.getTemplateUrl()); + if (templateFileInfo == null) { + DEException.throwException("Can't find the template's info from market,please check"); + } + templateStyle = templateFileInfo.getCanvasStyleData(); + templateData = templateFileInfo.getComponentData(); + dynamicData = templateFileInfo.getDynamicData(); + staticResource = templateFileInfo.getStaticResource(); + name = request.getName(); + dvType = request.getType(); + } + // 解析动态数据 + Map dynamicDataMap = JsonUtil.parseObject(dynamicData, Map.class); + List chartViews = new ArrayList<>(); + Map canvasViewInfo = new HashMap<>(); +// List viewsData = new ArrayList<>(); + for (Map.Entry entry : dynamicDataMap.entrySet()) { + String originViewId = entry.getKey(); + String originViewData = entry.getValue(); + ChartViewDTO chartView = JsonUtil.parseObject(originViewData, ChartViewDTO.class); + Long newViewId = IDUtils.snowID(); + chartView.setId(newViewId); + chartView.setSceneId(newDvId); + chartView.setDataFrom(CommonConstants.VIEW_DATA_FROM.TEMPLATE); + // 数据处理 1.替换viewId 2.加入panelView 数据(数据来源为template) 3.加入模板view data数据 + // viewsData.add(new PanelGroupExtendDataDTO(newPanelId, newViewId, originViewData)); + templateData = templateData.replaceAll(originViewId, newViewId.toString()); + chartViewManege.save(chartView); + canvasViewInfo.put(chartView.getId(),chartView); + } + request.setComponentData(templateData); + request.setCanvasStyleData(templateStyle); + //Store static resource into the server + staticResourceServer.saveFilesToServe(staticResource); + return new DataVisualizationVO(newDvId,name,dvType,templateStyle,templateData,canvasViewInfo); + } + + @Override + public DataVisualizationVO decompressionLocalFile(MultipartFile file) { + return null; + } + @Override public void nameCheck(DataVisualizationBaseRequest request) { 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 e8b15d3238..74118a1f43 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 @@ -14,4 +14,22 @@ CREATE TABLE `visualization_template` ( `template_data` longtext COMMENT 'template 数据', `dynamic_data` longtext COMMENT '预存数据', PRIMARY KEY (`id`) -); \ No newline at end of file +); + +BEGIN; +INSERT INTO `core_menu` +VALUES (19, 0, 2, 'template-market', 'template-market', 4, NULL, '/template-market', 0, 1, 0); +INSERT INTO `core_menu` +VALUES (20, 15, 2, 'template-setting', 'system/template-setting', 4, 'icon_template', '/template-setting', 0, 1, 1); +COMMIT; + +DROP TABLE IF EXISTS `visualization_template_extend_data`; +CREATE TABLE `visualization_template_extend_data` ( + `id` bigint NOT NULL, + `dv_id` bigint DEFAULT NULL, + `view_id` bigint DEFAULT NULL, + `view_details` longtext, + `copy_from` varchar(255) DEFAULT NULL, + `copy_id` varchar(255) DEFAULT NULL, + PRIMARY KEY (`id`) +); 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 2df7f2aa01..bc45bca231 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 @@ -23,4 +23,15 @@ INSERT INTO `core_menu` VALUES (19, 0, 2, 'template-market', 'template-market', 4, NULL, '/template-market', 0, 1, 0); INSERT INTO `core_menu` VALUES (20, 15, 2, 'template-setting', 'system/template-setting', 4, 'icon_template', '/template-setting', 0, 1, 1); -COMMIT; \ No newline at end of file +COMMIT; + +DROP TABLE IF EXISTS `visualization_template_extend_data`; +CREATE TABLE `visualization_template_extend_data` ( + `id` bigint NOT NULL, + `dv_id` bigint DEFAULT NULL, + `view_id` bigint DEFAULT NULL, + `view_details` longtext, + `copy_from` varchar(255) DEFAULT NULL, + `copy_id` varchar(255) DEFAULT NULL, + PRIMARY KEY (`id`) +); diff --git a/core/core-backend/src/main/resources/mybatis/ExtVisualizationTemplateMapper.xml b/core/core-backend/src/main/resources/mybatis/ExtVisualizationTemplateMapper.xml new file mode 100644 index 0000000000..22e2623b47 --- /dev/null +++ b/core/core-backend/src/main/resources/mybatis/ExtVisualizationTemplateMapper.xml @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + visualization_template.id, visualization_template.`name`, visualization_template.pid, visualization_template.`level`,visualization_template.`dv_type`, visualization_template.node_type, visualization_template.create_by, visualization_template.create_time, visualization_template.template_type, visualization_template.snapshot + + + visualization_template.template_style, visualization_template.template_data, visualization_template.dynamic_data + + + + diff --git a/core/core-frontend/package.json b/core/core-frontend/package.json index 894f8a1546..d9ca0ae122 100644 --- a/core/core-frontend/package.json +++ b/core/core-frontend/package.json @@ -27,6 +27,7 @@ "deepmerge": "^4.3.1", "element-plus-secondary": "^0.4.10", "element-resize-detector": "^1.2.4", + "file-saver": "^2.0.5", "highcharts": "^10.3.3", "html-to-image": "^1.11.11", "html2canvas": "^1.4.1", diff --git a/core/core-frontend/src/api/template.ts b/core/core-frontend/src/api/template.ts index fdce516ca0..320cc93401 100644 --- a/core/core-frontend/src/api/template.ts +++ b/core/core-frontend/src/api/template.ts @@ -2,33 +2,33 @@ import request from '@/config/axios' export function save(data) { return request.post({ - url: '/template/save', + url: '/templateManage/save', data: data, loading: true }) } export function templateDelete(id) { return request.post({ - url: '/template/delete/' + id + url: '/templateManage/delete/' + id }) } export function showTemplateList(data) { return request.post({ - url: '/template/templateList', + url: '/templateManage/templateList', data: data }) } export function findOne(id) { return request.get({ - url: '/template/findOne/' + id + url: '/templateManage/findOne/' + id }) } export function find(data) { return request.post({ - url: '/template/find', + url: '/templateManage/find', data: data, loading: true }) @@ -36,7 +36,7 @@ export function find(data) { export function nameCheck(data) { return request.post({ - url: '/template/nameCheck', + url: '/templateManage/nameCheck', data: data }) } diff --git a/core/core-frontend/src/assets/none.png b/core/core-frontend/src/assets/none.png new file mode 100644 index 0000000000..700664ed24 Binary files /dev/null and b/core/core-frontend/src/assets/none.png differ diff --git a/core/core-frontend/src/assets/nothing.png b/core/core-frontend/src/assets/nothing.png new file mode 100644 index 0000000000..7b1fa548bf Binary files /dev/null and b/core/core-frontend/src/assets/nothing.png differ diff --git a/core/core-frontend/src/style/index.less b/core/core-frontend/src/style/index.less index ac16fb3c83..8d453f723d 100644 --- a/core/core-frontend/src/style/index.less +++ b/core/core-frontend/src/style/index.less @@ -361,3 +361,9 @@ em { background-color: #1F232999; } } + +.de-icon-sense { + margin-right: 9px; + width: 16px !important; + height: 12px !important; +} diff --git a/core/core-frontend/src/utils/imgUtils.ts b/core/core-frontend/src/utils/imgUtils.ts index 73f4c485c2..fc2f533c19 100644 --- a/core/core-frontend/src/utils/imgUtils.ts +++ b/core/core-frontend/src/utils/imgUtils.ts @@ -1,6 +1,11 @@ import html2canvas from 'html2canvas' import JsPDF from 'jspdf' - +import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain' +import { storeToRefs } from 'pinia' +import { findResourceAsBase64 } from '@/api/staticResource' +import FileSaver from 'file-saver' +const dvMainStore = dvMainStoreWithOut() +const { canvasStyleData, componentData, canvasViewInfo, dvInfo } = storeToRefs(dvMainStore) const basePath = import.meta.env.VITE_API_BASEPATH export function imgUrlTrans(url) { @@ -20,6 +25,37 @@ export function imgUrlTrans(url) { } } +export function download2AppTemplate(downloadType, canvasDom, name, callBack?) { + try { + findStaticSource(function (staticResource) { + html2canvas(canvasDom).then(canvas => { + const snapshot = canvas.toDataURL('image/jpeg', 0.1) // 0.1是图片质量 + if (snapshot !== '') { + const templateInfo = { + name: name, + templateType: 'self', + snapshot: snapshot, + dvType: dvInfo.value.type, + canvasStyleData: JSON.stringify(canvasStyleData.value), + componentData: JSON.stringify(componentData.value), + dynamicData: JSON.stringify(canvasViewInfo.value), + staticResource: JSON.stringify(staticResource || {}) + } + const blob = new Blob([JSON.stringify(templateInfo)], { type: '' }) + if (downloadType === 'template') { + FileSaver.saveAs(blob, name + '-TEMPLATE.DET2') + } + } + if (callBack) { + callBack() + } + }) + }) + } catch (e) { + console.error(e) + } +} + export function downloadCanvas(type, canvasDom, name, callBack?) { // const canvasDom = document.getElementById(canvasId) if (canvasDom) { @@ -56,15 +92,57 @@ export function downloadCanvas(type, canvasDom, name, callBack?) { } } -export function dataURLToBlob(dataurl) { +export function dataURLToBlob(dataUrl) { // ie 图片转格式 - const arr = dataurl.split(',') + const arr = dataUrl.split(',') const mime = arr[0].match(/:(.*?);/)[1] - const bstr = atob(arr[1]) - let n = bstr.length + const bStr = atob(arr[1]) + let n = bStr.length const u8arr = new Uint8Array(n) while (n--) { - u8arr[n] = bstr.charCodeAt(n) + u8arr[n] = bStr.charCodeAt(n) } return new Blob([u8arr], { type: mime }) } + +// 解析静态文件 +export function findStaticSource(callBack) { + const staticResource = [] + // 系统背景文件 + if ( + typeof canvasStyleData.value.background === 'string' && + canvasStyleData.value.background.indexOf('static-resource') > -1 + ) { + staticResource.push(canvasStyleData.value.background) + } + componentData.value.forEach(item => { + if ( + typeof item.commonBackground.outerImage === 'string' && + item.commonBackground.outerImage.indexOf('static-resource') > -1 + ) { + staticResource.push(item.commonBackground.outerImage) + } + if ( + item.component === 'Picture' && + item.propValue['url'] && + typeof item.propValue['url'] === 'string' && + item.propValue['url'].indexOf('static-resource') > -1 + ) { + staticResource.push(item.propValue) + } + }) + if (staticResource.length > 0) { + try { + findResourceAsBase64({ resourcePathList: staticResource }).then(rsp => { + callBack(rsp.data) + }) + } catch (e) { + console.error('findResourceAsBase64 error', e) + callBack() + } + } else { + setTimeout(() => { + callBack() + }, 0) + } +} diff --git a/core/core-frontend/src/views/dashboard/DashboardPreviewShow.vue b/core/core-frontend/src/views/dashboard/DashboardPreviewShow.vue index bcfdf1832d..c09810d72f 100644 --- a/core/core-frontend/src/views/dashboard/DashboardPreviewShow.vue +++ b/core/core-frontend/src/views/dashboard/DashboardPreviewShow.vue @@ -10,7 +10,7 @@ import { useRequestStoreWithOut } from '@/store/modules/request' import { usePermissionStoreWithOut } from '@/store/modules/permission' import { useMoveLine } from '@/hooks/web/useMoveLine' import { Icon } from '@/components/icon-custom' -import { downloadCanvas } from '@/utils/imgUtils' +import { download2AppTemplate, downloadCanvas } from '@/utils/imgUtils' const dvMainStore = dvMainStoreWithOut() const previewCanvasContainer = ref(null) @@ -89,7 +89,16 @@ const downloadH2 = type => { downloadCanvas(type, vueDom, state.dvInfo.name, () => { downloadStatus.value = false }) - }, 200) + }) +} + +const downloadAsAppTemplate = downloadType => { + nextTick(() => { + const vueDom = previewCanvasContainer.value.querySelector('.canvas-container') + download2AppTemplate(downloadType, vueDom, state.dvInfo.name, () => { + downloadStatus.value = false + }) + }) } const slideOpenChange = () => { @@ -155,7 +164,12 @@ defineExpose({ @@ -65,6 +65,7 @@ const state = reactive({ templateInfo: { level: '1', pid: props.pid, + dvType: 'dashboard', name: '', templateStyle: null, templateData: null, @@ -115,7 +116,7 @@ const saveTemplate = () => { type: 'primary', cb: () => save(state.templateInfo).then(response => { - ElMessage.success(t('system_parameter_setting.import_succeeded')) + ElMessage.success('导入成功') emits('refresh') emits('closeEditTemplateDialog') }), @@ -124,7 +125,7 @@ const saveTemplate = () => { handlerConfirm(options) } else { save(state.templateInfo).then(response => { - ElMessage.success(t('system_parameter_setting.import_succeeded')) + ElMessage.success(t('导入成功')) emits('refresh') emits('closeEditTemplateDialog') }) @@ -143,8 +144,9 @@ const handleFileChange = e => { const result = res.target.result as string state.importTemplateInfo = JSON.parse(result) state.templateInfo.name = state.importTemplateInfo['name'] - state.templateInfo.templateStyle = state.importTemplateInfo['panelStyle'] - state.templateInfo.templateData = state.importTemplateInfo['panelData'] + state.templateInfo.dvType = state.importTemplateInfo['dvType'] + state.templateInfo.templateStyle = state.importTemplateInfo['canvasStyleData'] + state.templateInfo.templateData = state.importTemplateInfo['componentData'] state.templateInfo.snapshot = state.importTemplateInfo.snapshot state.templateInfo.dynamicData = state.importTemplateInfo['dynamicData'] state.templateInfo.staticResource = state.importTemplateInfo['staticResource'] @@ -161,7 +163,7 @@ onMounted(() => { }) - diff --git a/core/core-frontend/src/views/template/component/TemplateList.vue b/core/core-frontend/src/views/template/component/DeTemplateList.vue similarity index 87% rename from core/core-frontend/src/views/template/component/TemplateList.vue rename to core/core-frontend/src/views/template/component/DeTemplateList.vue index aae066c3f4..771d302f41 100644 --- a/core/core-frontend/src/views/template/component/TemplateList.vue +++ b/core/core-frontend/src/views/template/component/DeTemplateList.vue @@ -2,24 +2,26 @@
  • - + + + {{ ele.name }} @@ -38,13 +42,13 @@ @@ -59,7 +63,7 @@ secondary @click="add()" > - {{ t('panel.add_category') }} + {{ t('visualization.add_category') }}
@@ -67,6 +71,8 @@ diff --git a/core/core-frontend/src/views/template/index.vue b/core/core-frontend/src/views/template/index.vue index f2a442c47d..7b2b2fab36 100644 --- a/core/core-frontend/src/views/template/index.vue +++ b/core/core-frontend/src/views/template/index.vue @@ -1,21 +1,21 @@ - - + - { if (nameRepeat(value)) { @@ -160,7 +162,7 @@ const state = reactive({ formType: '', originName: '', templateDialog: { - title: t('panel.import_template'), + title: t('visualization.import_template'), visible: false, pid: '' } @@ -251,14 +253,10 @@ const showTemplateEditDialog = (type, templateInfo) => { state.formType = type if (type === 'edit') { state.templateEditForm = JSON.parse(JSON.stringify(templateInfo)) - state.dialogTitle = t( - `system_parameter_setting.${ - state.templateEditForm['nodeType'] === 'folder' ? 'edit_classification' : 'edit_template' - }` - ) + state.dialogTitle = state.templateEditForm['nodeType'] === 'folder' ? '编辑分类' : '编辑模版' state.originName = state.templateEditForm['label'] } else { - state.dialogTitle = t('panel.add_category') + state.dialogTitle = t('visualization.add_category') state.templateEditForm = { name: '', nodeType: 'folder', @@ -266,11 +264,7 @@ const showTemplateEditDialog = (type, templateInfo) => { level: 0 } } - state.dialogTitleLabel = t( - `system_parameter_setting.${ - state.templateEditForm['nodeType'] === 'folder' ? 'classification_name' : 'template_name' - }` - ) + state.dialogTitleLabel = state.templateEditForm['nodeType'] === 'folder' ? '分类名称' : '模版名称' state.editTemplate = true } @@ -300,13 +294,15 @@ const close = () => { state.editTemplate = false } const getTree = () => { - const request = { - templateType: state.currentTemplateType, - level: '0' - } - find(request).then(res => { - state.templateList = res.data - showFirst() + nextTick(() => { + const request = { + templateType: state.currentTemplateType, + level: '0' + } + find(request).then(res => { + state.templateList = res.data + showFirst() + }) }) } const showFirst = () => { @@ -367,6 +363,7 @@ onMounted(() => { } .flex-tabs { + margin-top: 16px; display: flex; background: #f5f6f7; } diff --git a/sdk/api/api-base/src/main/java/io/dataease/api/template/TemplateManageApi.java b/sdk/api/api-base/src/main/java/io/dataease/api/template/TemplateManageApi.java index 6716678803..2dc3452e63 100644 --- a/sdk/api/api-base/src/main/java/io/dataease/api/template/TemplateManageApi.java +++ b/sdk/api/api-base/src/main/java/io/dataease/api/template/TemplateManageApi.java @@ -9,7 +9,7 @@ import java.util.List; public interface TemplateManageApi { @PostMapping("/templateList") - List templateList(); + List templateList(TemplateManageRequest request); @PostMapping("/save") TemplateManageDTO save(@RequestBody TemplateManageRequest request); diff --git a/sdk/api/api-base/src/main/java/io/dataease/api/template/dto/TemplateManageFileDTO.java b/sdk/api/api-base/src/main/java/io/dataease/api/template/dto/TemplateManageFileDTO.java new file mode 100644 index 0000000000..1b9c692f02 --- /dev/null +++ b/sdk/api/api-base/src/main/java/io/dataease/api/template/dto/TemplateManageFileDTO.java @@ -0,0 +1,26 @@ +package io.dataease.api.template.dto; + + +import io.dataease.api.template.vo.VisualizationTemplateVO; +import lombok.Data; + +import java.util.List; + + +@Data +public class TemplateManageFileDTO extends VisualizationTemplateVO { + + /** + * 样式数据 + */ + private String canvasStyleData; + + /** + * 组件数据 + */ + private String componentData; + + + private String staticResource; + +} diff --git a/sdk/api/api-base/src/main/java/io/dataease/api/visualization/DataVisualizationApi.java b/sdk/api/api-base/src/main/java/io/dataease/api/visualization/DataVisualizationApi.java index b7b8f288f0..0b8817daad 100644 --- a/sdk/api/api-base/src/main/java/io/dataease/api/visualization/DataVisualizationApi.java +++ b/sdk/api/api-base/src/main/java/io/dataease/api/visualization/DataVisualizationApi.java @@ -11,6 +11,7 @@ import io.dataease.auth.DePermit; import io.dataease.model.BusiNodeRequest; import io.dataease.model.BusiNodeVO; import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; import java.util.List; @@ -63,4 +64,21 @@ public interface DataVisualizationApi { @GetMapping("/findDvType/{dvId}") String findDvType(@PathVariable("dvId")Long dvId); + + /** + * 从模版解压可视化资源 模版来源包括 模版市场、内部模版管理 + * + * @return + */ + @PostMapping("/decompression") + DataVisualizationVO decompression(@RequestBody DataVisualizationBaseRequest request) throws Exception; + + /** + * 从模版解压可视化资源 模版来源包括本地上传 + * + * @return + */ + @PostMapping("/decompressionLocalFile") + DataVisualizationVO decompressionLocalFile(@RequestPart(value = "file") MultipartFile file); + } diff --git a/sdk/api/api-base/src/main/java/io/dataease/api/visualization/request/DataVisualizationBaseRequest.java b/sdk/api/api-base/src/main/java/io/dataease/api/visualization/request/DataVisualizationBaseRequest.java index 20977a3bb9..caff3bd810 100644 --- a/sdk/api/api-base/src/main/java/io/dataease/api/visualization/request/DataVisualizationBaseRequest.java +++ b/sdk/api/api-base/src/main/java/io/dataease/api/visualization/request/DataVisualizationBaseRequest.java @@ -10,4 +10,16 @@ public class DataVisualizationBaseRequest extends DataVisualizationVO { private Boolean moveFromUpdate = false; + private String optType; + + private String newFrom; + + private String dynamicData; + + private String templateId; + + private String staticResource; + + private String templateUrl; + } 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 5298c53c9f..f0921799d6 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 @@ -4,6 +4,7 @@ import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import io.dataease.api.chart.dto.ChartViewDTO; import lombok.Data; +import lombok.NoArgsConstructor; import java.io.Serializable; import java.util.HashMap; @@ -11,6 +12,7 @@ import java.util.List; import java.util.Map; @Data +@NoArgsConstructor public class DataVisualizationVO implements Serializable { @JsonSerialize(using = ToStringSerializer.class) @@ -120,4 +122,13 @@ public class DataVisualizationVO implements Serializable { * 视图基本信息 */ private Map canvasViewInfo = new HashMap<>(); + + public DataVisualizationVO(Long id, String name, String type, String canvasStyleData, String componentData, Map canvasViewInfo) { + this.id = id; + this.name = name; + this.type = type; + this.canvasStyleData = canvasStyleData; + this.componentData = componentData; + this.canvasViewInfo = canvasViewInfo; + } }