forked from github/dataease
Merge branch 'dev-v2' into pr@dev-v2_dzz
This commit is contained in:
commit
ea19bc38b0
@ -211,7 +211,7 @@ public class DatasetDataManage {
|
||||
}
|
||||
|
||||
public Long getDatasetTotal(Long datasetGroupId) throws Exception {
|
||||
DatasetGroupInfoDTO dto = datasetGroupManage.get(datasetGroupId, null);
|
||||
DatasetGroupInfoDTO dto = datasetGroupManage.getForCount(datasetGroupId);
|
||||
if (StringUtils.equalsIgnoreCase(dto.getNodeType(), "dataset")) {
|
||||
return getDatasetTotal(dto);
|
||||
}
|
||||
|
@ -346,6 +346,30 @@ public class DatasetGroupManage {
|
||||
}
|
||||
}
|
||||
|
||||
public DatasetGroupInfoDTO getForCount(Long id) throws Exception {
|
||||
CoreDatasetGroup coreDatasetGroup = coreDatasetGroupMapper.selectById(id);
|
||||
if (coreDatasetGroup == null) {
|
||||
return null;
|
||||
}
|
||||
DatasetGroupInfoDTO dto = new DatasetGroupInfoDTO();
|
||||
BeanUtils.copyBean(dto, coreDatasetGroup);
|
||||
if (StringUtils.equalsIgnoreCase(dto.getNodeType(), "dataset")) {
|
||||
dto.setUnion(JsonUtil.parseList(coreDatasetGroup.getInfo(), new TypeReference<>() {
|
||||
}));
|
||||
// 获取field
|
||||
List<DatasetTableFieldDTO> dsFields = datasetTableFieldManage.selectByDatasetGroupId(id);
|
||||
List<DatasetTableFieldDTO> allFields = dsFields.stream().map(ele -> {
|
||||
DatasetTableFieldDTO datasetTableFieldDTO = new DatasetTableFieldDTO();
|
||||
BeanUtils.copyBean(datasetTableFieldDTO, ele);
|
||||
datasetTableFieldDTO.setFieldShortName(ele.getDataeaseName());
|
||||
return datasetTableFieldDTO;
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
dto.setAllFields(allFields);
|
||||
}
|
||||
return dto;
|
||||
}
|
||||
|
||||
public DatasetGroupInfoDTO get(Long id, String type) throws Exception {
|
||||
CoreDatasetGroup coreDatasetGroup = coreDatasetGroupMapper.selectById(id);
|
||||
if (coreDatasetGroup == null) {
|
||||
|
@ -11,7 +11,6 @@ import io.dataease.menu.dao.auto.mapper.CoreMenuMapper;
|
||||
import io.dataease.utils.BeanUtils;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@ -19,8 +18,6 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static io.dataease.constant.CacheConstant.OrgCacheConstant.CORE_MENU_CACHE;
|
||||
|
||||
@Component
|
||||
public class MenuManage {
|
||||
|
||||
@ -39,7 +36,7 @@ public class MenuManage {
|
||||
return convertTree(treeNodes);
|
||||
}
|
||||
|
||||
// @Cacheable(cacheNames = CORE_MENU_CACHE, key = "'-dataease-'")
|
||||
// @Cacheable(cacheNames = CORE_MENU_CACHE, key = "'-dataease-'")
|
||||
public List<CoreMenu> coreMenus() {
|
||||
QueryWrapper<CoreMenu> wrapper = new QueryWrapper<>();
|
||||
wrapper.orderByAsc("menu_sort");
|
||||
@ -67,7 +64,7 @@ public class MenuManage {
|
||||
if (CollectionUtil.isNotEmpty(children = menuTreeNode.getChildren())) {
|
||||
vo.setChildren(convertTree(children));
|
||||
}
|
||||
if (CollectionUtil.isNotEmpty(children) || menuTreeNode.getType() != 1) {
|
||||
if (CollectionUtil.isNotEmpty(vo.getChildren()) || menuTreeNode.getType() != 1) {
|
||||
result.add(vo);
|
||||
}
|
||||
}
|
||||
@ -91,6 +88,14 @@ public class MenuManage {
|
||||
}
|
||||
|
||||
private boolean isXpackMenu(CoreMenu coreMenu) {
|
||||
return coreMenu.getId().equals(7L) || coreMenu.getPid().equals(7L) || coreMenu.getId().equals(14L) || coreMenu.getId().equals(17L) || coreMenu.getId().equals(18L);
|
||||
return coreMenu.getId().equals(7L)
|
||||
|| coreMenu.getPid().equals(7L)
|
||||
|| coreMenu.getId().equals(14L)
|
||||
|| coreMenu.getId().equals(17L)
|
||||
|| coreMenu.getId().equals(18L)
|
||||
|| coreMenu.getId().equals(21L)
|
||||
|| coreMenu.getPid().equals(21L)
|
||||
|| coreMenu.getId().equals(25L)
|
||||
|| coreMenu.getId().equals(26L);
|
||||
}
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ public class SysParameterManage {
|
||||
|
||||
public Map<String,String> groupVal(String groupKey) {
|
||||
QueryWrapper<CoreSysSetting> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.likeLeft("pkey", groupKey);
|
||||
queryWrapper.like("pkey", groupKey);
|
||||
List<CoreSysSetting> sysSettings = coreSysSettingMapper.selectList(queryWrapper);
|
||||
if (!CollectionUtils.isEmpty(sysSettings)) {
|
||||
return sysSettings.stream().collect(Collectors.toMap(CoreSysSetting::getPkey, CoreSysSetting::getPval));
|
||||
|
@ -1,10 +1,10 @@
|
||||
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.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.exception.DEException;
|
||||
import io.dataease.system.manage.SysParameterManage;
|
||||
@ -16,6 +16,7 @@ import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -28,8 +29,12 @@ import java.util.stream.Collectors;
|
||||
public class TemplateMarketManage {
|
||||
|
||||
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;
|
||||
|
||||
@ -41,7 +46,7 @@ public class TemplateMarketManage {
|
||||
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);
|
||||
return JsonUtil.parseObject(templateInfo, TemplateManageFileDTO.class);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
@ -57,26 +62,46 @@ public class TemplateMarketManage {
|
||||
return HttpClientUtil.get(url, config);
|
||||
}
|
||||
|
||||
public MarketBaseResponse searchTemplate(TemplateMarketSearchRequest request) {
|
||||
public MarketBaseResponse searchTemplate() {
|
||||
try {
|
||||
Map<String,String> templateParams = sysParameterManage.groupVal("template.");
|
||||
String result = marketGet(templateParams.get("template.url") + POSTS_API, templateParams.get("template.accessKey"));
|
||||
TypeReference<List<TemplateMarketDTO>> market = new TypeReference<>() {
|
||||
};
|
||||
List<TemplateMarketDTO> postsResult = JsonUtil.parseList(result,market);
|
||||
return new MarketBaseResponse(templateParams.get("template.url"), postsResult);
|
||||
Map<String, String> templateParams = sysParameterManage.groupVal("template.");
|
||||
String result = marketGet(templateParams.get("template.url") + POSTS_API_V2, null);
|
||||
MarketTemplateV2BaseResponse postsResult = JsonUtil.parseObject(result, MarketTemplateV2BaseResponse.class);
|
||||
return baseResponseV2Trans(postsResult, templateParams.get("template.url"));
|
||||
} catch (Exception e) {
|
||||
DEException.throwException(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<String> getCategories() {
|
||||
Map<String,String> templateParams = sysParameterManage.groupVal("template.");
|
||||
private MarketBaseResponse baseResponseV2Trans(MarketTemplateV2BaseResponse v2BaseResponse, String url) {
|
||||
Map<String, String> categoriesMap = getCategoriesBaseV2();
|
||||
List<TemplateMarketDTO> contents = new ArrayList<>();
|
||||
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())));
|
||||
});
|
||||
return new MarketBaseResponse(url, contents);
|
||||
}
|
||||
|
||||
public MarketBaseResponse searchTemplateV1() {
|
||||
try {
|
||||
Map<String, String> templateParams = sysParameterManage.groupVal("template.");
|
||||
String result = marketGet(templateParams.get("template.url") + POSTS_API, templateParams.get("template.accessKey"));
|
||||
MarketTemplateBaseResponse postsResult = JsonUtil.parseObject(result, MarketTemplateBaseResponse.class);
|
||||
MarketBaseResponse response = new MarketBaseResponse(templateParams.get("template.url"), postsResult.getData().getContent());
|
||||
return response;
|
||||
} catch (Exception e) {
|
||||
DEException.throwException(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<String> getCategoriesV1() {
|
||||
Map<String, String> templateParams = sysParameterManage.groupVal("template.");
|
||||
String resultStr = marketGet(templateParams.get("template.url") + CATEGORIES_API, templateParams.get("template.accessKey"));
|
||||
TypeReference<List<TemplateCategoryVO>> market = new TypeReference<>() {
|
||||
};
|
||||
List<TemplateCategoryVO> categories = JsonUtil.parseList(resultStr,market);
|
||||
MarketCategoryBaseResponse categoryBaseResponse = JsonUtil.parseObject(resultStr, MarketCategoryBaseResponse.class);
|
||||
List<TemplateCategoryVO> categories = categoryBaseResponse.getData();
|
||||
if (CollectionUtils.isNotEmpty(categories)) {
|
||||
return categories.stream().filter(item -> !"应用系列".equals(item.getName())).sorted(Comparator.comparing(TemplateCategoryVO::getPriority)).map(TemplateCategoryVO::getName).collect(Collectors.toList());
|
||||
} else {
|
||||
@ -84,4 +109,23 @@ public class TemplateMarketManage {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public List<String> getCategories() {
|
||||
return getCategoriesV2().stream().map(MarketMetaDataVO::getLabel)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public Map<String, String> getCategoriesBaseV2() {
|
||||
Map<String, String> categories = getCategoriesV2().stream()
|
||||
.collect(Collectors.toMap(MarketMetaDataVO::getSlug, MarketMetaDataVO::getLabel));
|
||||
return categories;
|
||||
}
|
||||
|
||||
public List<MarketMetaDataVO> getCategoriesV2() {
|
||||
Map<String, String> templateParams = sysParameterManage.groupVal("template.");
|
||||
String resultStr = marketGet(templateParams.get("template.url") + TEMPLATE_META_DATA_URL, null);
|
||||
MarketMetaDataBaseResponse metaData = JsonUtil.parseObject(resultStr, MarketMetaDataBaseResponse.class);
|
||||
List<MarketMetaDataVO> categories = metaData.getLabels();
|
||||
return categories;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,31 @@
|
||||
package io.dataease.template.service;
|
||||
|
||||
import io.dataease.api.template.TemplateMarketApi;
|
||||
import io.dataease.api.template.response.MarketBaseResponse;
|
||||
import io.dataease.template.manage.TemplateMarketManage;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author : WangJiaHao
|
||||
* @date : 2023/11/17 13:20
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/templateMarket")
|
||||
public class TemplateMarketService implements TemplateMarketApi {
|
||||
|
||||
@Resource
|
||||
private TemplateMarketManage templateMarketManage;
|
||||
@Override
|
||||
public MarketBaseResponse searchTemplate() {
|
||||
return templateMarketManage.searchTemplate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> categories() {
|
||||
return templateMarketManage.getCategories();
|
||||
}
|
||||
}
|
@ -255,8 +255,8 @@ public class DataVisualizationServer implements DataVisualizationApi {
|
||||
templateData = templateFileInfo.getComponentData();
|
||||
dynamicData = templateFileInfo.getDynamicData();
|
||||
staticResource = templateFileInfo.getStaticResource();
|
||||
name = request.getName();
|
||||
dvType = request.getType();
|
||||
name = templateFileInfo.getName();
|
||||
dvType = templateFileInfo.getDvType();
|
||||
}
|
||||
// 解析动态数据
|
||||
Map<String, String> dynamicDataMap = JsonUtil.parseObject(dynamicData, Map.class);
|
||||
|
@ -1,6 +1,6 @@
|
||||
spring:
|
||||
datasource:
|
||||
url: jdbc:mysql://localhost:3306/dataease?autoReconnect=false&useUnicode=true&characterEncoding=UTF-8&characterSetResults=UTF-8&zeroDateTimeBehavior=convertToNull&useSSL=false
|
||||
url: jdbc:mysql://localhost:3306/dataease?autoReconnect=false&useUnicode=true&characterEncoding=UTF-8&characterSetResults=UTF-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true
|
||||
username: root
|
||||
password: 123456
|
||||
messages:
|
||||
|
@ -18,6 +18,12 @@ i18n_menu.datasource=\u6570\u636E\u6E90
|
||||
i18n_menu.user=\u7528\u6237\u7BA1\u7406
|
||||
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.task=\u4EFB\u52A1\u7BA1\u7406
|
||||
i18n_menu.embedded=\u5D4C\u5165\u5F0F\u7BA1\u7406
|
||||
i18n_menu.platform=\u5E73\u53F0\u5BF9\u63A5
|
||||
i18n_field_name_repeat=\u6709\u91CD\u590D\u5B57\u6BB5\u540D\uFF1A
|
||||
i18n_pid_not_eq_id=\u79FB\u52A8\u76EE\u6807\u4E0D\u80FD\u662F\u81EA\u5DF1\u6216\u5B50\u76EE\u5F55
|
||||
i18n_ds_name_exists=\u8BE5\u5206\u7EC4\u4E0B\u540D\u79F0\u91CD\u590D
|
||||
|
13
core/core-frontend/src/api/templateMarket.ts
Normal file
13
core/core-frontend/src/api/templateMarket.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import request from '@/config/axios'
|
||||
|
||||
export function searchMarket() {
|
||||
return request.get({
|
||||
url: '/templateMarket/search'
|
||||
})
|
||||
}
|
||||
|
||||
export function getCategories() {
|
||||
return request.get({
|
||||
url: '/templateMarket/categories'
|
||||
})
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
import request from '@/config/axios'
|
||||
|
||||
export function searchMarket(data) {
|
||||
return request.post({
|
||||
url: '/template/market/search',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function getCategories() {
|
||||
return request.post({
|
||||
url: '/template/market/categories'
|
||||
})
|
||||
}
|
3
core/core-frontend/src/assets/svg/dv-use-template.svg
Normal file
3
core/core-frontend/src/assets/svg/dv-use-template.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M17.0855 1.00006H4C3.73478 1.00006 3.48043 1.10542 3.29289 1.29295C3.10536 1.48049 3 1.73484 3 2.00006V22.0001C3 22.2653 3.10536 22.5196 3.29289 22.7072C3.48043 22.8947 3.73478 23.0001 4 23.0001H20C20.2652 23.0001 20.5196 22.8947 20.7071 22.7072C20.8946 22.5196 21 22.2653 21 22.0001V4.91556C21.0001 4.65044 20.8949 4.39614 20.7075 4.20856L17.793 1.29306C17.7001 1.20014 17.5898 1.12643 17.4684 1.07616C17.347 1.02588 17.2169 1.00002 17.0855 1.00006ZM7 8.5C7 8.22386 7.22386 8 7.5 8H16.5C16.7761 8 17 8.22386 17 8.5V9.5C17 9.77614 16.7761 10 16.5 10H7.5C7.22386 10 7 9.77614 7 9.5V8.5ZM11 12.5C11 12.2239 11.2239 12 11.5 12H16.5C16.7761 12 17 12.2239 17 12.5V17.5C17 17.7761 16.7761 18 16.5 18H11.5C11.2239 18 11 17.7761 11 17.5V12.5ZM7 12.5C7 12.2239 7.22386 12 7.5 12H8.5C8.77614 12 9 12.2239 9 12.5V17.5C9 17.7761 8.77614 18 8.5 18H7.5C7.22386 18 7 17.7761 7 17.5V12.5Z" fill="#FF8800"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.0 KiB |
4
core/core-frontend/src/assets/svg/embedded.svg
Normal file
4
core/core-frontend/src/assets/svg/embedded.svg
Normal file
@ -0,0 +1,4 @@
|
||||
<svg width="18" height="16" viewBox="0 0 18 16" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M9.22368 0.225297L17.6143 5.56475C17.8715 5.72848 17.8715 6.10407 17.6143 6.2678L9.22369 11.6073C9.0872 11.6941 8.91278 11.6941 8.77629 11.6073L0.385719 6.2678C0.128427 6.10407 0.128427 5.72848 0.385718 5.56475L8.77629 0.225297C8.91278 0.138443 9.0872 0.138443 9.22368 0.225297ZM2.9377 5.91628L8.99999 9.77409L15.0623 5.91628L8.99999 2.05846L2.9377 5.91628Z" />
|
||||
<path d="M1.16368 9.57137C0.967505 9.45108 0.71096 9.51261 0.590674 9.70879L0.155081 10.4192C0.0347947 10.6154 0.0963176 10.8719 0.292496 10.9922L7.92179 15.6701C8.4571 15.9983 9.12617 15.9983 9.66148 15.6701L17.2908 10.9922C17.487 10.8719 17.5485 10.6154 17.4282 10.4192L16.9926 9.70879C16.8723 9.51261 16.6158 9.45108 16.4196 9.57137L8.90053 14.1816C8.83371 14.2226 8.74955 14.2226 8.68274 14.1816L1.16368 9.57137Z" />
|
||||
</svg>
|
After Width: | Height: | Size: 883 B |
1
core/core-frontend/src/assets/svg/platform.svg
Normal file
1
core/core-frontend/src/assets/svg/platform.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg class="icon" width="200px" height="200.00px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M314.49 3.082H157.692C70.793 3.082 0 74.073 0 161.271V864.32c0 87.198 70.792 158.189 157.592 158.189H314.49c86.9 0 157.592-70.991 157.592-158.189V702.652h-72.98V864.32c0 46.93-37.98 84.91-84.612 84.91H157.693c-46.731 0-84.613-38.18-84.613-84.91V161.27c0-46.929 37.981-84.91 84.613-84.91h156.896c46.73 0 84.612 38.18 84.612 84.91v159.68h72.98V161.27c-0.1-87.197-70.793-158.188-157.692-158.188z m546.252 0H703.746c-86.899 0-157.592 70.991-157.592 158.189v159.68h72.98V161.27c0-46.93 37.981-84.911 84.612-84.911h156.896c46.731 0 84.613 38.18 84.613 84.91v703.05c0 46.93-37.981 84.91-84.613 84.91H703.746c-46.73 0-84.612-38.18-84.612-84.91V702.652h-72.98V864.32c0 87.198 70.792 158.189 157.592 158.189h156.896c86.9 0 157.592-70.991 157.592-158.189V161.27c0.1-87.197-70.692-158.188-157.492-158.188z m0 0" /><path d="M191.995 485.602H461.84c-0.596-27.74-23.465-50.31-51.304-50.31H186.129c-28.238 0-51.305 23.166-51.305 51.503v105.492c0 28.337 23.067 51.504 51.305 51.504h224.506c28.237 0 51.305-23.167 51.305-51.504v-1.093H191.995V485.602z m0 0" /><path d="M395.423 512.447h230.074v46.035H395.423z" /><path d="M556.395 485.602H826.34v105.492H556.395v1.094c0 28.337 23.067 51.503 51.305 51.503h224.506c28.238 0 51.305-23.166 51.305-51.503V486.696c0-28.337-23.067-51.503-51.305-51.503H607.7c-27.84 0.099-50.708 22.669-51.305 50.41z m0 0" /></svg>
|
After Width: | Height: | Size: 1.6 KiB |
3
core/core-frontend/src/assets/svg/sync.svg
Normal file
3
core/core-frontend/src/assets/svg/sync.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg width="20" height="16" viewBox="0 0 20 16" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10.8333 14.25H7.08325C3.63147 14.25 0.833252 11.4518 0.833252 8.00003C0.833252 5.52942 2.26677 3.39363 4.34741 2.37905L5.18374 3.82761C3.60043 4.54958 2.49992 6.14629 2.49992 8.00003C2.49992 10.5313 4.55195 12.5834 7.08325 12.5834H10.8333V11.4642C10.8333 11.2226 11.0291 11.0267 11.2708 11.0267C11.3767 11.0267 11.4791 11.0651 11.5588 11.1349L13.7903 13.0874C13.9721 13.2466 13.9906 13.5229 13.8315 13.7048C13.8187 13.7194 13.8049 13.7332 13.7903 13.7459L11.5588 15.6985C11.377 15.8576 11.1006 15.8391 10.9415 15.6573C10.8717 15.5776 10.8333 15.4752 10.8333 15.3692V14.25ZM9.16659 3.41671V4.53589C9.16659 4.64187 9.12813 4.74424 9.05834 4.82399C8.89923 5.00583 8.62284 5.02426 8.44099 4.86515L6.20955 2.91263C6.19493 2.89984 6.18118 2.88609 6.16839 2.87147C6.00928 2.68963 6.0277 2.41324 6.20955 2.25413L8.44099 0.301607C8.52075 0.231824 8.62312 0.193359 8.72909 0.193359C8.97071 0.193359 9.16659 0.389235 9.16659 0.630859V1.75004H12.9166C16.3684 1.75004 19.1666 4.54826 19.1666 8.00004C19.1666 10.4527 17.7539 12.5753 15.6978 13.5987L14.862 12.1512C16.4207 11.4195 17.4999 9.8358 17.4999 8.00004C17.4999 5.46874 15.4479 3.41671 12.9166 3.41671H9.16659Z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
@ -6,7 +6,7 @@ import { snapshotStoreWithOut } from '@/store/modules/data-visualization/snapsho
|
||||
import { changeSizeWithScale } from '@/utils/changeComponentsSizeWithScale'
|
||||
import { useEmitt } from '@/hooks/web/useEmitt'
|
||||
const dvMainStore = dvMainStoreWithOut()
|
||||
const { canvasStyleData } = storeToRefs(dvMainStore)
|
||||
const { canvasStyleData, editMode } = storeToRefs(dvMainStore)
|
||||
const snapshotStore = snapshotStoreWithOut()
|
||||
const scale = ref(60)
|
||||
|
||||
@ -42,6 +42,9 @@ const reposition = () => {
|
||||
let lastWheelNum = 0
|
||||
|
||||
const handleMouseWheel = e => {
|
||||
if (editMode.value === 'preview') {
|
||||
return
|
||||
}
|
||||
let dvMain = document.getElementById('dv-main-center')
|
||||
let dvMainLeftSlide = document.getElementById('dv-main-left-sidebar')
|
||||
let areaLeftWidth = dvMainLeftSlide.clientWidth
|
||||
@ -86,6 +89,7 @@ onUnmounted(() => {
|
||||
:min="10"
|
||||
:max="200"
|
||||
:controls="false"
|
||||
@change="handleScaleChange()"
|
||||
class="scale-input-number"
|
||||
>
|
||||
<template #suffix> % </template>
|
||||
|
@ -101,7 +101,7 @@
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in state.sourceLinkageInfo.targetViewFields"
|
||||
v-for="item in sourceLinkageInfoFilter"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
@ -184,7 +184,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { queryVisualizationJumpInfo } from '@/api/visualization/linkJump'
|
||||
import { reactive, ref, nextTick, watch } from 'vue'
|
||||
import { reactive, ref, nextTick, watch, computed } from 'vue'
|
||||
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { ElMessage } from 'element-plus-secondary'
|
||||
@ -379,6 +379,22 @@ const linkageFieldAdaptor = async data => {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const sourceLinkageInfoFilter = computed(() => {
|
||||
if (state.sourceLinkageInfo.targetViewFields) {
|
||||
const curCheckAllAxisStr =
|
||||
JSON.stringify(state.curLinkageViewInfo.xAxis) +
|
||||
JSON.stringify(state.curLinkageViewInfo.xAxisExt) +
|
||||
JSON.stringify(state.curLinkageViewInfo.yAxis) +
|
||||
JSON.stringify(state.curLinkageViewInfo.yAxisExt)
|
||||
return state.sourceLinkageInfo.targetViewFields.filter(item =>
|
||||
curCheckAllAxisStr.includes(item.id)
|
||||
)
|
||||
} else {
|
||||
return []
|
||||
}
|
||||
})
|
||||
|
||||
const targetViewCheckedChange = data => {
|
||||
nextTick(() => {
|
||||
linkageInfoTree.value.setCurrentKey(data.targetViewId)
|
||||
|
@ -335,7 +335,6 @@ const calcData = (view: Chart, callback) => {
|
||||
}
|
||||
|
||||
const initCurFields = chartDetails => {
|
||||
curFields.value = []
|
||||
dataRowFiledName.value = []
|
||||
dataRowSelect.value = {}
|
||||
dataRowNameSelect.value = {}
|
||||
@ -347,10 +346,12 @@ const initCurFields = chartDetails => {
|
||||
JSON.stringify(chartDetails.yAxisExt)
|
||||
chartDetails.data.sourceFields.forEach(field => {
|
||||
if (checkAllAxisStr.indexOf(field.id) > -1) {
|
||||
curFields.value.push(field)
|
||||
dataRowFiledName.value.push(`[${field.name}]`)
|
||||
}
|
||||
})
|
||||
if (checkAllAxisStr.indexOf('"记录数*"') > -1) {
|
||||
dataRowFiledName.value.push(`[记录数*]`)
|
||||
}
|
||||
// Get the corresponding relationship between id and value
|
||||
const nameIdMap = chartDetails.data.fields.reduce((pre, next) => {
|
||||
pre[next['dataeaseName']] = next['id']
|
||||
|
@ -952,6 +952,7 @@ export default {
|
||||
field_can_not_empty: '字段不能为空',
|
||||
conditions_can_not_empty: '字段的条件不能为空,若无条件,请直接删除该字段',
|
||||
remark: '备注',
|
||||
remark_placeholder: '备注限制50个字符',
|
||||
remark_show: '显示备注',
|
||||
remark_edit: '编辑备注',
|
||||
remark_bg_color: '背景填充',
|
||||
|
22
core/core-frontend/src/utils/RemoteJs.ts
Normal file
22
core/core-frontend/src/utils/RemoteJs.ts
Normal file
@ -0,0 +1,22 @@
|
||||
export const loadScript = (url: string, jsId?: string) => {
|
||||
return new Promise(function (resolve, reject) {
|
||||
const scriptId = jsId || 'de-fit2cloud-script-id'
|
||||
let dom = document.getElementById(scriptId)
|
||||
if (dom) {
|
||||
dom.parentElement?.removeChild(dom)
|
||||
dom = null
|
||||
}
|
||||
const script = document.createElement('script')
|
||||
|
||||
script.id = scriptId
|
||||
script.onload = function () {
|
||||
return resolve(null)
|
||||
}
|
||||
script.onerror = function () {
|
||||
return reject(new Error('Load script from '.concat(url, ' failed')))
|
||||
}
|
||||
script.src = url
|
||||
const head = document.head || document.getElementsByTagName('head')[0]
|
||||
;(document.body || head).appendChild(script)
|
||||
})
|
||||
}
|
@ -18,9 +18,8 @@ import { storeToRefs } from 'pinia'
|
||||
import { BASE_VIEW_CONFIG } from '../util/chart'
|
||||
import { cloneDeep, defaultsDeep } from 'lodash-es'
|
||||
const dvMainStore = dvMainStoreWithOut()
|
||||
const { dvInfo } = storeToRefs(dvMainStore)
|
||||
|
||||
const { nowPanelTrackInfo, nowPanelJumpInfo } = storeToRefs(dvMainStore)
|
||||
const { nowPanelTrackInfo, nowPanelJumpInfo, dvInfo } = storeToRefs(dvMainStore)
|
||||
|
||||
const { t } = useI18n()
|
||||
const linkJumpRef = ref(null)
|
||||
@ -154,7 +153,7 @@ const noSenior = computed(() => {
|
||||
const linkJumpActiveChange = () => {
|
||||
// 直接触发刷新
|
||||
const params = {
|
||||
sourceDvId: chart.value.sceneId,
|
||||
sourceDvId: dvInfo.value.id,
|
||||
sourceViewId: chart.value.id,
|
||||
activeStatus: chart.value.jumpActive
|
||||
}
|
||||
@ -164,7 +163,7 @@ const linkJumpActiveChange = () => {
|
||||
}
|
||||
const linkageActiveChange = () => {
|
||||
const params = {
|
||||
dvId: chart.value.sceneId,
|
||||
dvId: dvInfo.value.id,
|
||||
sourceViewId: chart.value.id,
|
||||
activeStatus: chart.value.linkageActive
|
||||
}
|
||||
|
@ -358,7 +358,14 @@ watch(
|
||||
>
|
||||
<div @keydown.stop @keyup.stop>
|
||||
<el-form-item :label="t('chart.remark')" class="form-item" prop="chartShowName">
|
||||
<el-input type="textarea" autosize v-model="tempRemark" :maxlength="50" clearable />
|
||||
<el-input
|
||||
type="textarea"
|
||||
autosize
|
||||
v-model="tempRemark"
|
||||
:maxlength="50"
|
||||
clearable
|
||||
:placeholder="t('chart.remark_placeholder')"
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<template #footer>
|
||||
|
@ -78,6 +78,7 @@ export class Map extends L7PlotChartView<ChoroplethOptions, Choropleth> {
|
||||
}
|
||||
const geoJson = cloneDeep(await getGeoJsonFile(areaId))
|
||||
let options: ChoroplethOptions = {
|
||||
preserveDrawingBuffer: true,
|
||||
map: {
|
||||
type: 'mapbox',
|
||||
style: 'blank'
|
||||
|
@ -101,15 +101,19 @@ const state = reactive({
|
||||
templateCreatePid: 0
|
||||
})
|
||||
|
||||
const dvSvgType = computed(() =>
|
||||
curCanvasType.value === 'dashboard' ? 'dv-dashboard-spine' : 'dv-screen-spine'
|
||||
)
|
||||
|
||||
state.resourceTypeList = [
|
||||
{
|
||||
label: newResourceLabel,
|
||||
svgName: curCanvasType.value === 'dashboard' ? 'dv-dashboard-spine' : 'dv-screen-spine',
|
||||
label: '空白新建',
|
||||
svgName: dvSvgType.value,
|
||||
command: 'newLeaf'
|
||||
},
|
||||
{
|
||||
label: '从模版新建',
|
||||
svgName: curCanvasType.value === 'dashboard' ? 'dv-dashboard-spine' : 'dv-screen-spine',
|
||||
label: '使用模版新建',
|
||||
svgName: 'dv-use-template',
|
||||
command: 'newFromTemplate'
|
||||
},
|
||||
{
|
||||
@ -247,7 +251,7 @@ const addOperation = (
|
||||
window.open(baseUrl, '_blank')
|
||||
}
|
||||
} else if (cmd === 'newFromTemplate') {
|
||||
state.templateCreatePid = data.id
|
||||
state.templateCreatePid = data?.id
|
||||
// newFromTemplate
|
||||
resourceCreateOpt.value.optInit()
|
||||
} else {
|
||||
@ -337,11 +341,28 @@ defineExpose({
|
||||
<Icon name="dv-new-folder" />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
<el-tooltip :content="newResourceLabel" placement="top" effect="dark">
|
||||
<el-icon class="custom-icon btn" @click="addOperation('newLeaf', null, 'leaf', true)">
|
||||
|
||||
<el-dropdown popper-class="menu-outer-dv_popper" trigger="click">
|
||||
<el-icon class="custom-icon btn" @click.stop>
|
||||
<Icon name="icon_file-add_outlined" />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item @click="addOperation('newLeaf', null, 'leaf', true)">
|
||||
<el-icon class="handle-icon">
|
||||
<Icon :name="dvSvgType"></Icon>
|
||||
</el-icon>
|
||||
空白新建
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item @click="addOperation('newFromTemplate', null, 'leaf', true)">
|
||||
<el-icon class="handle-icon">
|
||||
<Icon name="dv-use-template"></Icon>
|
||||
</el-icon>
|
||||
使用模版新建
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
<el-input
|
||||
@ -459,6 +480,7 @@ defineExpose({
|
||||
line-height: 24px;
|
||||
}
|
||||
.custom-icon {
|
||||
font-size: 20px;
|
||||
&.btn {
|
||||
color: #3370ff;
|
||||
}
|
||||
@ -539,3 +561,10 @@ defineExpose({
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="less">
|
||||
.menu-outer-dv_popper {
|
||||
width: 140px;
|
||||
margin-top: -2px !important;
|
||||
}
|
||||
</style>
|
||||
|
@ -98,7 +98,7 @@ watch(
|
||||
:weight="dvInfo.weight"
|
||||
:resource-type="dvInfo.type"
|
||||
/>
|
||||
<el-button v-if="dvInfo.weight > 6" type="primary" @click="dvEdit()">
|
||||
<el-button class="custom-button" v-if="dvInfo.weight > 6" type="primary" @click="dvEdit()">
|
||||
<template #icon>
|
||||
<icon name="icon_edit_outlined"></icon>
|
||||
</template>
|
||||
@ -176,4 +176,8 @@ watch(
|
||||
font-size: 16px;
|
||||
color: #646a73;
|
||||
}
|
||||
|
||||
.custom-button {
|
||||
margin-left: 12px;
|
||||
}
|
||||
</style>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<div class="info-template-container">
|
||||
<div class="info-template-header">
|
||||
<div class="info-template-title">
|
||||
<span>基础设置</span>
|
||||
<span>{{ curTitle }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<el-button type="primary" @click="edit">{{ t('commons.edit') }}</el-button>
|
||||
@ -40,7 +40,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, defineProps, PropType } from 'vue'
|
||||
import { ref, defineProps, PropType, computed } from 'vue'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { SettingRecord, ToolTipRecord } from './SettingTemplate'
|
||||
const { t } = useI18n()
|
||||
@ -52,9 +52,29 @@ const props = defineProps({
|
||||
labelTooltips: {
|
||||
type: Array as PropType<ToolTipRecord[]>,
|
||||
default: () => []
|
||||
},
|
||||
settingData: {
|
||||
type: Array as PropType<SettingRecord[]>,
|
||||
default: () => []
|
||||
},
|
||||
settingTitle: {
|
||||
type: String,
|
||||
default: '基础设置'
|
||||
}
|
||||
})
|
||||
|
||||
const curTitle = computed(() => {
|
||||
return props.settingTitle
|
||||
})
|
||||
|
||||
const loadList = () => {
|
||||
if (props.settingData?.length) {
|
||||
props.settingData.forEach(item => {
|
||||
settingList.value.push(item)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const settingList = ref([] as SettingRecord[])
|
||||
|
||||
const loadBasic = () => {
|
||||
@ -136,6 +156,9 @@ const init = () => {
|
||||
if (props.settingKey === 'email') {
|
||||
loadEmail()
|
||||
}
|
||||
if (props.settingData?.length) {
|
||||
loadList()
|
||||
}
|
||||
}
|
||||
const pwdItem = ref({})
|
||||
|
||||
|
@ -1,5 +1,10 @@
|
||||
<template>
|
||||
<InfoTemplate :label-tooltips="tooltips" setting-key="basic" @edit="edit" />
|
||||
<InfoTemplate
|
||||
:label-tooltips="tooltips"
|
||||
setting-key="basic"
|
||||
setting-title="基础设置"
|
||||
@edit="edit"
|
||||
/>
|
||||
<basic-edit ref="editor" />
|
||||
</template>
|
||||
|
||||
|
@ -1,5 +1,10 @@
|
||||
<template>
|
||||
<InfoTemplate :label-tooltips="tooltips" setting-key="email" @edit="edit" />
|
||||
<InfoTemplate
|
||||
:label-tooltips="tooltips"
|
||||
setting-title="邮件设置"
|
||||
setting-key="email"
|
||||
@edit="edit"
|
||||
/>
|
||||
<email-edit ref="editor" />
|
||||
</template>
|
||||
|
||||
|
@ -0,0 +1,494 @@
|
||||
<template>
|
||||
<el-row style="width: 100%">
|
||||
<el-row style="display: table; width: 100%">
|
||||
<el-col style="float: left" :class="state.asideActive ? 'aside-active' : 'aside-inActive'">
|
||||
<el-icon v-show="!state.asideActive" class="insert" @click="asideActiveChange(true)"
|
||||
><DArrowRight
|
||||
/></el-icon>
|
||||
<el-row v-show="state.asideActive" style="padding: 12px 12px 0">
|
||||
<el-row style="align-items: center">
|
||||
<el-icon class="insert" @click="closePreview()"><Close /></el-icon>
|
||||
<span class="main-title">{{ t('visualization.template_preview') }}</span>
|
||||
<el-icon class="insert" @click="asideActiveChange(false)"><DArrowLeft /></el-icon>
|
||||
</el-row>
|
||||
<el-row class="margin-top16 search-area">
|
||||
<el-input
|
||||
v-model="state.searchText"
|
||||
size="small"
|
||||
prefix-icon="Search"
|
||||
class="title-name-search"
|
||||
:placeholder="t('visualization.enter_template_name_tips')"
|
||||
clearable="true"
|
||||
/>
|
||||
<el-icon
|
||||
class="insert-filter filter-icon-span"
|
||||
:class="state.extFilterActive ? 'filter-icon-active' : ''"
|
||||
@click="extFilterActiveChange()"
|
||||
><Filter
|
||||
/></el-icon>
|
||||
</el-row>
|
||||
<el-row v-show="state.extFilterActive">
|
||||
<el-select
|
||||
v-model="state.marketActiveTab"
|
||||
class="margin-top16"
|
||||
size="small"
|
||||
placeholder="请选择"
|
||||
>
|
||||
<el-option v-for="item in state.marketTabs" :key="item" :label="item" :value="item" />
|
||||
</el-select>
|
||||
</el-row>
|
||||
<el-divider />
|
||||
</el-row>
|
||||
|
||||
<el-row
|
||||
v-show="state.asideActive"
|
||||
class="aside-list"
|
||||
:class="state.extFilterActive ? 'aside-list-filter-active' : ''"
|
||||
>
|
||||
<template-market-preview-item
|
||||
v-for="templateItem in state.currentMarketTemplateShowList"
|
||||
v-show="templateItem.showFlag"
|
||||
:key="templateItem.id"
|
||||
:template="templateItem"
|
||||
:base-url="state.baseUrl"
|
||||
:active="active(templateItem)"
|
||||
@previewTemplate="previewTemplate"
|
||||
/>
|
||||
<el-row v-show="!state.hasResult" class="custom-position">
|
||||
<div style="text-align: center">
|
||||
<Icon name="no_result" style="margin-bottom: 16px; font-size: 75px"></Icon>
|
||||
<br />
|
||||
<span>{{ t('commons.no_result') }}</span>
|
||||
</div>
|
||||
</el-row>
|
||||
</el-row>
|
||||
</el-col>
|
||||
<el-col
|
||||
style="float: left"
|
||||
class="main-area"
|
||||
:class="state.asideActive ? 'main-area-active' : ''"
|
||||
>
|
||||
<el-row>
|
||||
<span v-if="state.curTemplate" class="template-title">{{ state.curTemplate.title }}</span>
|
||||
<div style="flex: 1; text-align: right">
|
||||
<el-button
|
||||
style="float: right"
|
||||
type="primary"
|
||||
size="small"
|
||||
@click="templateApply(state.curTemplate)"
|
||||
>{{ t('visualization.apply_this_template') }}</el-button
|
||||
>
|
||||
</div>
|
||||
</el-row>
|
||||
<el-row class="img-main">
|
||||
<img style="height: 100%" :src="state.templatePreviewUrl" alt="" />
|
||||
</el-row>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { searchMarket, getCategories } from '@/api/templateMarket'
|
||||
import { onMounted, reactive, watch } from 'vue'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import TemplateMarketPreviewItem from '@/views/template-market/component/TemplateMarketPreviewItem.vue'
|
||||
const { t } = useI18n()
|
||||
|
||||
const props = defineProps({
|
||||
previewId: {
|
||||
type: String,
|
||||
default: null
|
||||
}
|
||||
})
|
||||
|
||||
const emits = defineEmits(['templateApply', 'closeDialog', 'closePreview'])
|
||||
|
||||
const state = reactive({
|
||||
hasResult: true,
|
||||
extFilterActive: false,
|
||||
asideActive: true,
|
||||
previewVisible: false,
|
||||
templatePreviewUrl: null,
|
||||
marketTabs: null,
|
||||
marketActiveTab: null,
|
||||
searchText: null,
|
||||
panelGroupList: [],
|
||||
curApplyTemplate: null,
|
||||
folderSelectShow: false,
|
||||
baseUrl: 'https://dataease.io/templates',
|
||||
currentMarketTemplateShowList: [],
|
||||
networkStatus: true,
|
||||
curTemplate: null
|
||||
})
|
||||
|
||||
watch(
|
||||
() => state.marketActiveTab,
|
||||
value => {
|
||||
initTemplateShow()
|
||||
}
|
||||
)
|
||||
|
||||
watch(
|
||||
() => state.searchText,
|
||||
value => {
|
||||
initTemplateShow()
|
||||
}
|
||||
)
|
||||
|
||||
watch(
|
||||
() => props.previewId,
|
||||
value => {
|
||||
state.currentMarketTemplateShowList.forEach(template => {
|
||||
if (value === template.id) {
|
||||
previewTemplate(template)
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
const initMarketTemplate = () => {
|
||||
searchMarket()
|
||||
.then(rsp => {
|
||||
state.baseUrl = rsp.data.baseUrl
|
||||
state.currentMarketTemplateShowList = rsp.data.contents
|
||||
state.hasResult = true
|
||||
})
|
||||
.catch(() => {
|
||||
state.networkStatus = false
|
||||
})
|
||||
getCategories()
|
||||
.then(rsp => {
|
||||
state.marketTabs = rsp.data
|
||||
state.marketActiveTab = state.marketTabs[0]
|
||||
})
|
||||
.catch(() => {
|
||||
state.networkStatus = false
|
||||
})
|
||||
if (props.previewId) {
|
||||
state.currentMarketTemplateShowList.forEach(template => {
|
||||
if (props.previewId === template.id) {
|
||||
previewTemplate(template)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const getGroupTree = () => {
|
||||
// do getGroupTree
|
||||
}
|
||||
|
||||
const normalizer = node => {
|
||||
// 去掉children=null的属性
|
||||
if (node.children === null || node.children === 'null') {
|
||||
delete node.children
|
||||
}
|
||||
}
|
||||
|
||||
const templateApply = template => {
|
||||
emits('templateApply', template)
|
||||
}
|
||||
|
||||
const closeDialog = () => {
|
||||
emits('closeDialog')
|
||||
}
|
||||
|
||||
const handleClick = item => {
|
||||
//handleClick
|
||||
}
|
||||
|
||||
const initTemplateShow = () => {
|
||||
state.hasResult = false
|
||||
state.currentMarketTemplateShowList.forEach(template => {
|
||||
template.showFlag = templateShow(template)
|
||||
if (template.showFlag) {
|
||||
state.hasResult = true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const templateShow = templateItem => {
|
||||
let categoryMarch = false
|
||||
let searchMarch = false
|
||||
templateItem.categories.forEach(category => {
|
||||
if (category.name === state.marketActiveTab) {
|
||||
categoryMarch = true
|
||||
}
|
||||
})
|
||||
if (!state.searchText || templateItem.title.indexOf(state.searchText) > -1) {
|
||||
searchMarch = true
|
||||
}
|
||||
return categoryMarch && searchMarch
|
||||
}
|
||||
|
||||
const previewTemplate = template => {
|
||||
state.curTemplate = template
|
||||
if (template.thumbnail.indexOf('http') > -1) {
|
||||
state.templatePreviewUrl = template.thumbnail
|
||||
} else {
|
||||
state.templatePreviewUrl = state.baseUrl + template.thumbnail
|
||||
}
|
||||
}
|
||||
|
||||
const asideActiveChange = prop => {
|
||||
state.asideActive = prop
|
||||
}
|
||||
|
||||
const extFilterActiveChange = () => {
|
||||
state.extFilterActive = !state.extFilterActive
|
||||
state.marketActiveTab = state.marketTabs[0]
|
||||
}
|
||||
const closePreview = () => {
|
||||
emits('closePreview')
|
||||
}
|
||||
|
||||
const active = template => {
|
||||
return state.curTemplate && state.curTemplate.id === template.id
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
initMarketTemplate()
|
||||
getGroupTree()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.aside-list {
|
||||
padding: 0px 12px 12px 12px;
|
||||
width: 100%;
|
||||
height: calc(100vh - 200px);
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.aside-list-filter-active {
|
||||
height: calc(100vh - 250px);
|
||||
}
|
||||
|
||||
.template-main {
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 0 2px 0 rgba(31, 31, 31, 0.15), 0 1px 2px 0 rgba(31, 31, 31, 0.15);
|
||||
border: solid 2px #fff;
|
||||
padding-bottom: 24px;
|
||||
min-height: calc(100vh - 190px);
|
||||
}
|
||||
|
||||
.market-main {
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
.title-left {
|
||||
float: left;
|
||||
font-size: 20px;
|
||||
font-weight: 500;
|
||||
line-height: 28px;
|
||||
}
|
||||
|
||||
.title-right {
|
||||
float: right;
|
||||
width: 320px;
|
||||
}
|
||||
|
||||
.dialog-footer-self {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.search-button-self {
|
||||
text-align: left;
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.topbar-icon-active {
|
||||
cursor: pointer;
|
||||
transition: 0.1s;
|
||||
border-radius: 3px;
|
||||
font-size: 22px;
|
||||
background-color: rgb(245, 245, 245);
|
||||
|
||||
&:active {
|
||||
color: #000;
|
||||
border-color: #3a8ee6;
|
||||
background-color: red;
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(31, 35, 41, 0.1);
|
||||
color: #3a8ee6;
|
||||
}
|
||||
}
|
||||
|
||||
.custom-position {
|
||||
height: 70vh;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 14px;
|
||||
flex-flow: row nowrap;
|
||||
color: #646a73;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.aside-active {
|
||||
width: 206px;
|
||||
height: calc(100vh - 56px);
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
background-color: var(--ContentBG, #ffffff);
|
||||
}
|
||||
|
||||
.aside-inActive {
|
||||
position: relative;
|
||||
width: 0px;
|
||||
}
|
||||
|
||||
.main-area-active {
|
||||
width: calc(100% - 206px) !important;
|
||||
}
|
||||
|
||||
.main-area {
|
||||
width: 100%;
|
||||
padding: 24px;
|
||||
text-align: center;
|
||||
height: calc(100vh - 56px);
|
||||
transition: 0.5s;
|
||||
}
|
||||
|
||||
.title-name-search {
|
||||
width: 140px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.icon20 {
|
||||
font-size: 20px !important;
|
||||
}
|
||||
|
||||
.main-title {
|
||||
width: 135px;
|
||||
margin-left: 8px;
|
||||
font-weight: 500;
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
color: var(--TextPrimary, #1f2329);
|
||||
}
|
||||
|
||||
.insert-filter {
|
||||
display: inline-block;
|
||||
font-weight: 400 !important;
|
||||
font-family: PingFang SC;
|
||||
line-height: 1;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
color: var(--TextPrimary, #1f2329);
|
||||
-webkit-appearance: none;
|
||||
text-align: center;
|
||||
box-sizing: border-box;
|
||||
outline: 0;
|
||||
margin: 0;
|
||||
transition: 0.1s;
|
||||
border-radius: 3px;
|
||||
|
||||
&:active {
|
||||
color: #000;
|
||||
border-color: #3a8ee6;
|
||||
background-color: red;
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(31, 35, 41, 0.1);
|
||||
color: #3a8ee6;
|
||||
}
|
||||
}
|
||||
|
||||
.insert {
|
||||
display: inline-block;
|
||||
font-weight: 400 !important;
|
||||
font-family: PingFang SC;
|
||||
line-height: 1;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
color: #646a73;
|
||||
-webkit-appearance: none;
|
||||
text-align: center;
|
||||
box-sizing: border-box;
|
||||
outline: 0;
|
||||
margin: 0;
|
||||
transition: 0.1s;
|
||||
border-radius: 3px;
|
||||
|
||||
&:active {
|
||||
color: #000;
|
||||
border-color: #3a8ee6;
|
||||
background-color: red;
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(31, 35, 41, 0.1);
|
||||
color: #3a8ee6;
|
||||
}
|
||||
}
|
||||
|
||||
.template-title {
|
||||
float: left;
|
||||
font-weight: 500;
|
||||
font-size: 20px;
|
||||
line-height: 28px;
|
||||
margin-bottom: 24px;
|
||||
color: var(--TextPrimary, #1f2329);
|
||||
}
|
||||
|
||||
.margin-top16 {
|
||||
margin-top: 16px;
|
||||
}
|
||||
.img-main {
|
||||
display: inherit;
|
||||
border-radius: 4px;
|
||||
background: #0f1114;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
height: calc(100% - 50px) !important;
|
||||
}
|
||||
.open-button {
|
||||
cursor: pointer;
|
||||
font-size: 30px;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 16px;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
//.open-button:hover{
|
||||
// transition: 0.5s;
|
||||
// width: 50px;
|
||||
//}
|
||||
.open-button:hover {
|
||||
color: #3a8ee6;
|
||||
}
|
||||
.filter-icon-span {
|
||||
float: left;
|
||||
border: 1px solid #dcdfe6;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 4px;
|
||||
padding: 7px;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.filter-icon-active {
|
||||
border: 1px solid #3370ff;
|
||||
color: #3370ff;
|
||||
}
|
||||
|
||||
.filter-icon-active {
|
||||
border: 1px solid #3370ff;
|
||||
color: #3370ff;
|
||||
}
|
||||
|
||||
.search-area {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,122 @@
|
||||
<template>
|
||||
<div class="testcase-template">
|
||||
<div class="template-img" :style="classBackground" @click.stop="templateInnerPreview" />
|
||||
<el-row class="bottom-area">
|
||||
<el-row>
|
||||
<span class="demonstration">{{ template.title }}</span>
|
||||
</el-row>
|
||||
</el-row>
|
||||
<el-row class="template-button">
|
||||
<el-button size="mini" style="width: 141px" @click="templateInnerPreview">{{
|
||||
t('visualization.preview')
|
||||
}}</el-button>
|
||||
<el-button size="mini" style="width: 141px" type="primary" @click="apply">{{
|
||||
t('visualization.apply')
|
||||
}}</el-button>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { computed } from 'vue'
|
||||
import { imgUrlTrans } from '@/utils/imgUtils'
|
||||
const { t } = useI18n()
|
||||
|
||||
const emits = defineEmits(['templateApply', 'templatePreview'])
|
||||
|
||||
const props = defineProps({
|
||||
template: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
baseUrl: {
|
||||
type: String
|
||||
},
|
||||
width: {
|
||||
type: Number
|
||||
}
|
||||
})
|
||||
|
||||
const classBackground = computed(() => {
|
||||
return {
|
||||
width: props.width + 'px',
|
||||
height: props.width * 0.58 + 'px',
|
||||
background: `url(${imgUrlTrans(thumbnailUrl.value)}) no-repeat`,
|
||||
'background-size': `100% 100%`
|
||||
}
|
||||
})
|
||||
|
||||
const thumbnailUrl = computed(() => {
|
||||
if (props.template.thumbnail.indexOf('http') > -1) {
|
||||
return props.template.thumbnail
|
||||
} else {
|
||||
return props.baseUrl + props.template.thumbnail
|
||||
}
|
||||
})
|
||||
|
||||
const apply = () => {
|
||||
emits('templateApply', props.template)
|
||||
}
|
||||
|
||||
const templateInnerPreview = e => {
|
||||
emits('templatePreview', props.template.id)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.testcase-template {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
margin: 0;
|
||||
box-shadow: 0 0 2px 0 rgba(31, 31, 31, 0.15), 0 1px 2px 0 rgba(31, 31, 31, 0.15);
|
||||
border: solid 2px #fff;
|
||||
box-sizing: border-box;
|
||||
border-radius: 4px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.demonstration {
|
||||
display: block;
|
||||
font-size: 16px;
|
||||
text-align: left;
|
||||
margin-left: 12px;
|
||||
margin-top: 12px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
color: var(--TextPrimary, #1f2329);
|
||||
}
|
||||
|
||||
.template-img {
|
||||
background-size: 100% 100%;
|
||||
margin: 0 auto;
|
||||
border: solid 2px #fff;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.template-img:hover {
|
||||
border: solid 1px #4b8fdf;
|
||||
border-radius: 4px;
|
||||
color: deepskyblue;
|
||||
cursor: pointer;
|
||||
}
|
||||
.testcase-template:hover ::v-deep .template-button {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.template-button {
|
||||
display: none;
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
bottom: 5px;
|
||||
left: 0px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.bottom-area {
|
||||
height: 75px;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,105 @@
|
||||
<template>
|
||||
<div
|
||||
:class="[
|
||||
{
|
||||
['template-item-main-active']: active
|
||||
},
|
||||
'template-item-main'
|
||||
]"
|
||||
@click.stop="previewTemplate"
|
||||
>
|
||||
<div class="template-item-img" :style="classBackground" />
|
||||
<span class="demonstration">{{ template.title }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { imgUrlTrans } from '@/utils/imgUtils'
|
||||
import { computed } from 'vue'
|
||||
const emits = defineEmits(['previewTemplate'])
|
||||
|
||||
const props = defineProps({
|
||||
template: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
baseUrl: {
|
||||
type: String
|
||||
},
|
||||
active: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
}
|
||||
})
|
||||
|
||||
const classBackground = computed(() => {
|
||||
return {
|
||||
background: `url(${imgUrlTrans(thumbnailUrl.value)}) no-repeat`,
|
||||
'background-size': `100% 100%`
|
||||
}
|
||||
})
|
||||
|
||||
const thumbnailUrl = computed(() => {
|
||||
if (props.template.thumbnail.indexOf('http') > -1) {
|
||||
return props.template.thumbnail
|
||||
} else {
|
||||
return props.baseUrl + props.template.thumbnail
|
||||
}
|
||||
})
|
||||
|
||||
const previewTemplate = () => {
|
||||
emits('previewTemplate', props.template)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.template-item-main {
|
||||
margin: 0 0 12px 0;
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
width: 182px;
|
||||
height: 116px;
|
||||
background-color: var(--ContentBG, #ffffff);
|
||||
border: 1px solid #dee0e3;
|
||||
border-radius: 4px;
|
||||
flex: none;
|
||||
order: 0;
|
||||
flex-grow: 0;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.template-item-main-active {
|
||||
border: 2px solid #3370ff !important;
|
||||
}
|
||||
.template-item-img {
|
||||
position: absolute;
|
||||
width: 182px;
|
||||
height: 86px;
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
}
|
||||
|
||||
.demonstration {
|
||||
position: absolute;
|
||||
width: 166px;
|
||||
height: 20px;
|
||||
left: 8px;
|
||||
top: 91px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-size: 12px;
|
||||
line-height: 20px;
|
||||
display: block;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.template-item-main:hover {
|
||||
border: solid 1px #3370ff;
|
||||
}
|
||||
</style>
|
@ -1,35 +1,382 @@
|
||||
<template>
|
||||
<el-row class="custom-position template-main">
|
||||
{{ t('visualization.market_network_tips') }}
|
||||
<el-row class="outer-body" v-loading="state.loading">
|
||||
<!--预览模式-->
|
||||
<market-preview
|
||||
v-show="previewModel"
|
||||
:preview-id="state.templatePreviewId"
|
||||
@closePreview="closePreview"
|
||||
@templateApply="templateApply"
|
||||
/>
|
||||
<!--列表模式-->
|
||||
<el-row v-show="!previewModel" class="market-main">
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<span class="title-left">{{ t('visualization.template_market') }}</span>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-input
|
||||
v-model="state.searchText"
|
||||
prefix-icon="el-icon-search"
|
||||
size="small"
|
||||
class="title-right"
|
||||
:placeholder="t('visualization.enter_template_name_tips')"
|
||||
:clearable="true"
|
||||
/>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row class="custom-tabs-head">
|
||||
<el-tabs v-model="state.marketActiveTab" @tab-click="handleClick">
|
||||
<el-tab-pane
|
||||
v-for="tabItem in state.marketTabs"
|
||||
:key="tabItem"
|
||||
:label="tabItem"
|
||||
:name="tabItem"
|
||||
/>
|
||||
</el-tabs>
|
||||
</el-row>
|
||||
<el-row
|
||||
v-show="state.networkStatus && state.hasResult"
|
||||
id="template-main"
|
||||
class="template-main"
|
||||
>
|
||||
<el-col
|
||||
v-for="templateItem in state.currentMarketTemplateShowList"
|
||||
v-show="templateItem.showFlag"
|
||||
:key="templateItem.id"
|
||||
style="padding: 24px 12px 0; text-align: center; flex: 0"
|
||||
:style="{ width: state.templateSpan }"
|
||||
>
|
||||
<template-market-item
|
||||
:key="'outer-' + templateItem.id"
|
||||
:template="templateItem"
|
||||
:base-url="state.baseUrl"
|
||||
:width="state.templateCurWidth"
|
||||
@templateApply="templateApply"
|
||||
@templatePreview="templatePreview"
|
||||
/>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row
|
||||
v-show="state.networkStatus && !state.hasResult"
|
||||
class="custom-position template-main"
|
||||
>
|
||||
<div style="text-align: center">
|
||||
<Icon name="no_result" style="margin-bottom: 16px; font-size: 75px"></Icon>
|
||||
<br />
|
||||
<span>{{ t('commons.no_result') }}</span>
|
||||
</div>
|
||||
</el-row>
|
||||
<el-row v-show="!state.networkStatus" class="custom-position template-main">
|
||||
{{ t('visualization.market_network_tips') }}
|
||||
</el-row>
|
||||
</el-row>
|
||||
</el-row>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
|
||||
<script setup lang="ts">
|
||||
import { getCategories, searchMarket } from '@/api/templateMarket'
|
||||
import elementResizeDetectorMaker from 'element-resize-detector'
|
||||
import { nextTick, reactive, watch, onMounted, ref } from 'vue'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { ElMessage } from 'element-plus-secondary'
|
||||
import MarketPreview from '@/views/template-market/component/MarketPreview.vue'
|
||||
import TemplateMarketItem from '@/views/template-market/component/TemplateMarketItem.vue'
|
||||
import { decompression } from '@/api/visualization/dataVisualization'
|
||||
import { useCache } from '@/hooks/web/useCache'
|
||||
const { t } = useI18n()
|
||||
const { wsCache } = useCache()
|
||||
|
||||
const previewModel = ref(false)
|
||||
|
||||
const state = reactive({
|
||||
loading: false,
|
||||
hasResult: true,
|
||||
templateMiniWidth: 330,
|
||||
templateCurWidth: 310,
|
||||
templateSpan: '25%',
|
||||
previewVisible: false,
|
||||
templatePreviewId: '',
|
||||
marketTabs: null,
|
||||
marketActiveTab: null,
|
||||
searchText: null,
|
||||
dvCreateForm: {
|
||||
name: null,
|
||||
pid: null,
|
||||
nodeType: 'panel',
|
||||
templateUrl: null,
|
||||
newFrom: 'new_market_template',
|
||||
panelType: 'self',
|
||||
panelStyle: {},
|
||||
panelData: '[]'
|
||||
},
|
||||
panelGroupList: [],
|
||||
curApplyTemplate: null,
|
||||
folderSelectShow: false,
|
||||
baseUrl: 'https://dataease.io/templates',
|
||||
currentMarketTemplateShowList: [],
|
||||
networkStatus: true,
|
||||
rule: {
|
||||
name: [
|
||||
{
|
||||
required: true,
|
||||
message: t('visualization.template_name_tips'),
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
pid: [
|
||||
{
|
||||
required: true,
|
||||
message: '',
|
||||
trigger: 'blur'
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
watch(
|
||||
() => state.marketActiveTab,
|
||||
value => {
|
||||
initTemplateShow()
|
||||
}
|
||||
)
|
||||
|
||||
watch(
|
||||
() => state.searchText,
|
||||
value => {
|
||||
initTemplateShow()
|
||||
}
|
||||
)
|
||||
|
||||
const closePreview = () => {
|
||||
previewModel.value = false
|
||||
}
|
||||
|
||||
const initMarketTemplate = () => {
|
||||
searchMarket()
|
||||
.then(rsp => {
|
||||
state.baseUrl = rsp.data.baseUrl
|
||||
state.currentMarketTemplateShowList = rsp.data.contents
|
||||
})
|
||||
.catch(() => {
|
||||
state.networkStatus = false
|
||||
})
|
||||
getCategories()
|
||||
.then(rsp => {
|
||||
state.marketTabs = rsp.data
|
||||
state.marketActiveTab = state.marketTabs[0]
|
||||
})
|
||||
.catch(() => {
|
||||
state.networkStatus = false
|
||||
})
|
||||
}
|
||||
|
||||
const getGroupTree = () => {
|
||||
// do getGroupTree
|
||||
// groupTree({ nodeType: 'folder' }).then(res => {
|
||||
// state.panelGroupList = res.data
|
||||
// })
|
||||
}
|
||||
const normalizer = node => {
|
||||
// 去掉children=null的属性
|
||||
if (node.children === null || node.children === 'null') {
|
||||
delete node.children
|
||||
}
|
||||
}
|
||||
|
||||
const templateApply = template => {
|
||||
state.curApplyTemplate = template
|
||||
state.dvCreateForm.name = template.title
|
||||
state.dvCreateForm.templateUrl = template.metas.theme_repo
|
||||
apply()
|
||||
}
|
||||
|
||||
const apply = () => {
|
||||
if (!state.dvCreateForm.templateUrl) {
|
||||
ElMessage.warning('未获取模板下载链接请联系模板市场官方')
|
||||
return false
|
||||
}
|
||||
state.loading = true
|
||||
decompression(state.dvCreateForm)
|
||||
.then(response => {
|
||||
state.loading = false
|
||||
const templateData = response.data
|
||||
// do create
|
||||
wsCache.set(`de-template-data`, JSON.stringify(templateData))
|
||||
const baseUrl =
|
||||
templateData.type === 'dataV'
|
||||
? '#/dvCanvas?opt=create&createType=template'
|
||||
: '#/dashboard?opt=create&createType=template'
|
||||
window.open(baseUrl, '_blank')
|
||||
})
|
||||
.catch(() => {
|
||||
state.loading = false
|
||||
})
|
||||
}
|
||||
const handleClick = item => {
|
||||
// do handleClick
|
||||
}
|
||||
const initTemplateShow = () => {
|
||||
let tempHasResult = false
|
||||
state.currentMarketTemplateShowList.forEach(template => {
|
||||
template.showFlag = templateShow(template)
|
||||
if (template.showFlag) {
|
||||
tempHasResult = true
|
||||
}
|
||||
})
|
||||
if (state.currentMarketTemplateShowList.length > 0) {
|
||||
state.hasResult = tempHasResult
|
||||
}
|
||||
}
|
||||
|
||||
const templateShow = templateItem => {
|
||||
let categoryMarch = false
|
||||
let searchMarch = false
|
||||
templateItem.categories.forEach(category => {
|
||||
if (category.name === state.marketActiveTab) {
|
||||
categoryMarch = true
|
||||
}
|
||||
})
|
||||
if (!state.searchText || templateItem.title.indexOf(state.searchText) > -1) {
|
||||
searchMarch = true
|
||||
}
|
||||
return categoryMarch && searchMarch
|
||||
}
|
||||
|
||||
const templatePreview = previewId => {
|
||||
state.templatePreviewId = previewId
|
||||
previewModel.value = true
|
||||
}
|
||||
const newPanel = () => {
|
||||
// do newPanel
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
initMarketTemplate()
|
||||
getGroupTree()
|
||||
const erd = elementResizeDetectorMaker()
|
||||
const templateMainDom = document.getElementById('template-main')
|
||||
// 监听div变动事件
|
||||
if (templateMainDom) {
|
||||
erd.listenTo(templateMainDom, element => {
|
||||
nextTick(() => {
|
||||
const curSeparator = Math.trunc(templateMainDom.offsetWidth / state.templateMiniWidth)
|
||||
state.templateSpan =
|
||||
100 / Math.trunc(templateMainDom.offsetWidth / state.templateMiniWidth) + '%'
|
||||
state.templateCurWidth = Math.trunc(templateMainDom.offsetWidth / curSeparator) - 33
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.custom-position {
|
||||
height: 80vh;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-size: 14px;
|
||||
flex-flow: row nowrap;
|
||||
color: #646a73;
|
||||
font-weight: 400;
|
||||
.custom-tabs-head {
|
||||
display: inherit;
|
||||
padding-bottom: 15px;
|
||||
::v-deep(.ed-tabs__item) {
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.template-main {
|
||||
text-align: center;
|
||||
border-radius: 4px;
|
||||
padding: 0 12px 24px 12px;
|
||||
height: calc(100vh - 56px) !important;
|
||||
height: calc(100vh - 190px) !important;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
background-color: var(--ContentBG, #ffffff);
|
||||
}
|
||||
|
||||
.market-main {
|
||||
padding: 24px;
|
||||
display: inherit;
|
||||
}
|
||||
|
||||
.title-left {
|
||||
float: left;
|
||||
font-size: 20px;
|
||||
font-weight: 500;
|
||||
line-height: 28px;
|
||||
color: var(--TextPrimary, #1f2329);
|
||||
}
|
||||
|
||||
.title-right {
|
||||
float: right;
|
||||
width: 320px;
|
||||
}
|
||||
|
||||
.dialog-footer-self {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.search-button-self {
|
||||
text-align: left;
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.topbar-icon-active {
|
||||
cursor: pointer;
|
||||
transition: 0.1s;
|
||||
border-radius: 3px;
|
||||
font-size: 22px;
|
||||
background-color: rgb(245, 245, 245);
|
||||
|
||||
&:active {
|
||||
color: #000;
|
||||
border-color: #3a8ee6;
|
||||
background-color: red;
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(31, 35, 41, 0.1);
|
||||
color: #3a8ee6;
|
||||
}
|
||||
}
|
||||
|
||||
.custom-position {
|
||||
height: 80vh;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 14px;
|
||||
flex-flow: row nowrap;
|
||||
color: #646a73;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.outer-body {
|
||||
display: inherit;
|
||||
width: 100%;
|
||||
height: calc(100vh - 56px);
|
||||
background-color: var(--MainBG, #f5f6f7);
|
||||
}
|
||||
|
||||
.market-dialog-css {
|
||||
::v-deep(.ed-form-item__label) {
|
||||
width: 100% !important;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
::v-deep(.ed-form-item.is-required:not(.is-no-asterisk) > .ed-form-item__label:before) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
::v-deep(.ed-form-item.is-required:not(.is-no-asterisk) > .ed-form-item__label::after) {
|
||||
content: '*';
|
||||
color: #f54a45;
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
::v-deep(.ed-form-item__content) {
|
||||
margin-left: 0 !important;
|
||||
}
|
||||
|
||||
::v-deep(.vue-treeselect__input) {
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
2
de-xpack
2
de-xpack
@ -1 +1 @@
|
||||
Subproject commit a6f7aa3f644fe258d9ed14cca420c3f6c4aeb1cd
|
||||
Subproject commit 91e4019972ec96f7f672bb5da2156f54ca9d72ea
|
@ -1,5 +1,7 @@
|
||||
package io.dataease.api.chart.dto;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
@ -7,6 +9,7 @@ import lombok.Data;
|
||||
*/
|
||||
@Data
|
||||
public class ChartDimensionDTO {
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long id;
|
||||
private String value;
|
||||
}
|
||||
|
@ -0,0 +1,21 @@
|
||||
package io.dataease.api.lark.api;
|
||||
|
||||
import io.dataease.api.lark.dto.LarkTokenRequest;
|
||||
import io.dataease.api.lark.vo.LarkInfoVO;
|
||||
import io.dataease.api.lark.dto.LarkSettingCreator;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
|
||||
public interface LarkApi {
|
||||
|
||||
@GetMapping("/info")
|
||||
LarkInfoVO info();
|
||||
|
||||
@PostMapping("/create")
|
||||
void save(@RequestBody LarkSettingCreator creator);
|
||||
|
||||
@PostMapping("/token")
|
||||
String larkToken(@RequestBody LarkTokenRequest request);
|
||||
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package io.dataease.api.lark.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
public class LarkSettingCreator implements Serializable {
|
||||
|
||||
private String appId;
|
||||
|
||||
private String appSecret;
|
||||
|
||||
private String callBack;
|
||||
|
||||
private Boolean enable;
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package io.dataease.api.lark.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
public class LarkTokenRequest implements Serializable {
|
||||
|
||||
private String code;
|
||||
|
||||
private String state;
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package io.dataease.api.lark.vo;
|
||||
|
||||
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
public class LarkInfoVO implements Serializable {
|
||||
|
||||
private String appId;
|
||||
|
||||
private String appSecret;
|
||||
|
||||
private String callBack;
|
||||
|
||||
private Boolean enable;
|
||||
}
|
@ -14,8 +14,8 @@ import java.util.List;
|
||||
*/
|
||||
public interface TemplateMarketApi {
|
||||
|
||||
@PostMapping("/search")
|
||||
MarketBaseResponse searchTemplate(@RequestBody TemplateMarketSearchRequest request);
|
||||
@GetMapping("/search")
|
||||
MarketBaseResponse searchTemplate();
|
||||
|
||||
@GetMapping("/categories")
|
||||
List<String> categories();
|
||||
|
@ -3,10 +3,15 @@ package io.dataease.api.template.dto;
|
||||
import io.dataease.api.template.vo.MarketCategoryVO;
|
||||
import io.dataease.api.template.vo.MarketMetasVO;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class TemplateMarketDTO {
|
||||
private String id;
|
||||
private String title;
|
||||
@ -18,4 +23,12 @@ public class TemplateMarketDTO {
|
||||
private Boolean showFlag = true;
|
||||
private List<MarketCategoryVO> categories;
|
||||
private MarketMetasVO metas;
|
||||
|
||||
public TemplateMarketDTO(String id, String title,String themeRepo,String templateUrl,String categoryName) {
|
||||
this.id = id;
|
||||
this.title = title;
|
||||
this.categories = Arrays.asList(new MarketCategoryVO(categoryName),new MarketCategoryVO("全部"));
|
||||
this.metas = new MarketMetasVO(templateUrl);
|
||||
this.thumbnail = themeRepo;
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package io.dataease.api.template.response;
|
||||
|
||||
import io.dataease.api.template.dto.TemplateMarketDTO;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ -8,6 +9,7 @@ import java.util.List;
|
||||
* @author : WangJiaHao
|
||||
* @date : 2023/11/6 17:43
|
||||
*/
|
||||
@Data
|
||||
public class MarketBaseResponse {
|
||||
private String baseUrl;
|
||||
|
||||
@ -21,4 +23,6 @@ public class MarketBaseResponse {
|
||||
this.contents = contents;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,16 @@
|
||||
package io.dataease.api.template.response;
|
||||
|
||||
import io.dataease.api.template.vo.TemplateCategoryVO;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Author: wangjiahao
|
||||
* Date: 2022/7/15
|
||||
* Description:
|
||||
*/
|
||||
@Data
|
||||
public class MarketCategoryBaseResponse {
|
||||
private List<TemplateCategoryVO> data;
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package io.dataease.api.template.response;
|
||||
|
||||
import io.dataease.api.template.vo.MarketMetaDataVO;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Author: wangjiahao
|
||||
* Date: 2022/7/15
|
||||
* Description:
|
||||
*/
|
||||
@Data
|
||||
public class MarketMetaDataBaseResponse {
|
||||
|
||||
private List<MarketMetaDataVO> deVersion;
|
||||
|
||||
private List<MarketMetaDataVO> templateTypes;
|
||||
|
||||
private List<MarketMetaDataVO> labels;
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package io.dataease.api.template.response;
|
||||
|
||||
import io.dataease.api.template.dto.TemplateMarketDTO;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author : WangJiaHao
|
||||
* @date : 2023/11/17 13:41
|
||||
*/
|
||||
@Data
|
||||
public class MarketTemplateBaseResponse {
|
||||
|
||||
private MarketTemplateInnerResult data;
|
||||
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package io.dataease.api.template.response;
|
||||
|
||||
import io.dataease.api.template.dto.TemplateMarketDTO;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author : WangJiaHao
|
||||
* @date : 2023/11/17 13:41
|
||||
*/
|
||||
@Data
|
||||
public class MarketTemplateInnerResult {
|
||||
|
||||
private List<TemplateMarketDTO> content;
|
||||
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package io.dataease.api.template.response;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author : WangJiaHao
|
||||
* @date : 2023/11/17 13:41
|
||||
*/
|
||||
@Data
|
||||
public class MarketTemplateV2BaseResponse {
|
||||
|
||||
private List<MarketTemplateV2ItemResult> items;
|
||||
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package io.dataease.api.template.response;
|
||||
|
||||
import io.dataease.api.template.vo.MarketApplicationVO;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author : WangJiaHao
|
||||
* @date : 2023/11/17 13:41
|
||||
*/
|
||||
@Data
|
||||
public class MarketTemplateV2ItemResult {
|
||||
|
||||
private MarketApplicationVO application;
|
||||
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package io.dataease.api.template.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* Author: wangjiahao
|
||||
* Date: 2022/7/15
|
||||
* Description:
|
||||
*/
|
||||
@Data
|
||||
public class MarketApplicationSpecLinkVO {
|
||||
|
||||
private String name;
|
||||
|
||||
private String url;
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package io.dataease.api.template.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* Author: wangjiahao
|
||||
* Date: 2022/7/15
|
||||
* Description:
|
||||
*/
|
||||
@Data
|
||||
public class MarketApplicationSpecScreenshotBaseVO {
|
||||
private String url;
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package io.dataease.api.template.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Author: wangjiahao
|
||||
* Date: 2022/7/15
|
||||
* Description:
|
||||
*/
|
||||
@Data
|
||||
public class MarketApplicationSpecVO {
|
||||
|
||||
private String displayName;
|
||||
|
||||
private String type;
|
||||
|
||||
private String deVersion;
|
||||
|
||||
private String templateType;
|
||||
|
||||
private String label;
|
||||
|
||||
private String readmeName;
|
||||
|
||||
private List<MarketApplicationSpecScreenshotBaseVO> screenshots;
|
||||
|
||||
private List<MarketApplicationSpecLinkVO> links;
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package io.dataease.api.template.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* Author: wangjiahao
|
||||
* Date: 2022/7/15
|
||||
* Description:
|
||||
*/
|
||||
@Data
|
||||
public class MarketApplicationVO {
|
||||
private MarketApplicationSpecVO spec;
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package io.dataease.api.template.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* Author: wangjiahao
|
||||
@ -8,8 +9,13 @@ import lombok.Data;
|
||||
* Description:
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class MarketCategoryVO {
|
||||
private String id;
|
||||
private String name;
|
||||
private String slug;
|
||||
|
||||
public MarketCategoryVO(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,15 @@
|
||||
package io.dataease.api.template.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* Author: wangjiahao
|
||||
* Date: 2022/7/15
|
||||
* Description:
|
||||
*/
|
||||
@Data
|
||||
public class MarketMetaDataVO {
|
||||
private String slug;
|
||||
private String value;
|
||||
private String label;
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package io.dataease.api.template.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* Author: wangjiahao
|
||||
@ -8,6 +9,11 @@ import lombok.Data;
|
||||
* Description:
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class MarketMetasVO {
|
||||
private String theme_repo;
|
||||
|
||||
public MarketMetasVO(String theme_repo) {
|
||||
this.theme_repo = theme_repo;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,33 @@
|
||||
package io.dataease.api.permissions.embedded.api;
|
||||
|
||||
import io.dataease.api.permissions.embedded.dto.EmbeddedCreator;
|
||||
import io.dataease.api.permissions.embedded.dto.EmbeddedEditor;
|
||||
import io.dataease.api.permissions.embedded.dto.EmbeddedResetRequest;
|
||||
import io.dataease.api.permissions.embedded.vo.EmbeddedGridVO;
|
||||
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;
|
||||
|
||||
public interface EmbeddedApi {
|
||||
|
||||
@GetMapping("/queryGrid")
|
||||
List<EmbeddedGridVO> queryGrid();
|
||||
|
||||
@PostMapping("/create")
|
||||
void create(@RequestBody EmbeddedCreator creator);
|
||||
|
||||
@PostMapping("/edit")
|
||||
void edit(@RequestBody EmbeddedEditor editor);
|
||||
|
||||
@PostMapping("/delete/{id}")
|
||||
void delete(@PathVariable("id") Long id);
|
||||
|
||||
@PostMapping("/reset")
|
||||
void reset(@RequestBody EmbeddedResetRequest request);
|
||||
|
||||
@GetMapping("/domainList")
|
||||
List<String> domainList();
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package io.dataease.api.permissions.embedded.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
public class EmbeddedCreator implements Serializable {
|
||||
|
||||
private String name;
|
||||
|
||||
private String domain;
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package io.dataease.api.permissions.embedded.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
public class EmbeddedEditor implements Serializable {
|
||||
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
private String domain;
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package io.dataease.api.permissions.embedded.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
public class EmbeddedResetRequest implements Serializable {
|
||||
|
||||
private Long id;
|
||||
|
||||
private String appSecret;
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package io.dataease.api.permissions.embedded.vo;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
public class EmbeddedGridVO implements Serializable {
|
||||
|
||||
@JsonSerialize(using= ToStringSerializer.class)
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
private String appId;
|
||||
|
||||
private String appSecret;
|
||||
|
||||
private String domain;
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package io.dataease.auth.interceptor;
|
||||
|
||||
import io.dataease.constant.AuthConstant;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
@ -13,16 +14,20 @@ import java.util.List;
|
||||
@Configuration
|
||||
public class CorsConfig implements WebMvcConfigurer {
|
||||
|
||||
@Resource(name = "deCorsInterceptor")
|
||||
private CorsInterceptor corsInterceptor;
|
||||
|
||||
@Value("#{'${dataease.origin-list}'.split(',')}")
|
||||
private List<String> originList;
|
||||
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
registry.addInterceptor(new CorsInterceptor(originList)).addPathPatterns("/**");
|
||||
corsInterceptor.addOriginList(originList);
|
||||
registry.addInterceptor(corsInterceptor).addPathPatterns("/**");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configurePathMatch(PathMatchConfigurer configurer) {
|
||||
configurer.addPathPrefix(AuthConstant.DE_API_PREFIX, c -> c.isAnnotationPresent(RestController.class));
|
||||
configurer.addPathPrefix(AuthConstant.DE_API_PREFIX, c -> c.isAnnotationPresent(RestController.class) && c.getPackageName().startsWith("io.dataease"));
|
||||
}
|
||||
}
|
||||
|
@ -1,27 +1,73 @@
|
||||
package io.dataease.auth.interceptor;
|
||||
|
||||
import cn.hutool.core.util.ReflectUtil;
|
||||
import io.dataease.utils.CommonBeanFactory;
|
||||
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.web.servlet.HandlerInterceptor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Component("deCorsInterceptor")
|
||||
public class CorsInterceptor implements HandlerInterceptor {
|
||||
|
||||
|
||||
private List<String> originList;
|
||||
private final List<String> originList;
|
||||
|
||||
private final List<String> busiOriginList = new ArrayList<>();
|
||||
|
||||
private Class<?> aClass;
|
||||
|
||||
private Object bean;
|
||||
|
||||
|
||||
public CorsInterceptor(List<String> originList) {
|
||||
this.originList = originList;
|
||||
}
|
||||
|
||||
public void addOriginList(List<String> list) {
|
||||
List<String> strings = list.stream().filter(item -> !originList.contains(item)).toList();
|
||||
originList.addAll(strings);
|
||||
}
|
||||
|
||||
|
||||
public void addOriginList() {
|
||||
String className = "io.dataease.api.permissions.embedded.api.EmbeddedApi";
|
||||
String methodName = "domainList";
|
||||
if (ObjectUtils.isEmpty(aClass)) {
|
||||
try {
|
||||
aClass = Class.forName(className);
|
||||
} catch (ClassNotFoundException e) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (ObjectUtils.isEmpty(bean)) {
|
||||
bean = CommonBeanFactory.getBean(aClass);
|
||||
}
|
||||
if (ObjectUtils.isNotEmpty(bean)) {
|
||||
Object result = ReflectUtil.invoke(bean, methodName);
|
||||
if (ObjectUtils.isNotEmpty(result)) {
|
||||
List<String> list = (List<String>) result;
|
||||
if (CollectionUtils.isNotEmpty(list)) {
|
||||
List<String> strings = list.stream().filter(item -> !busiOriginList.contains(item)).toList();
|
||||
busiOriginList.addAll(strings);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||
|
||||
addOriginList();
|
||||
String origin = request.getHeader("Origin");
|
||||
boolean embedded = StringUtils.startsWithAny(request.getRequestURI(), "/assets/", "/js/");
|
||||
if ((StringUtils.isNotBlank(origin) && originList.contains(origin)) || embedded) {
|
||||
if ((StringUtils.isNotBlank(origin) && originList.contains(origin)) || busiOriginList.contains(origin) || embedded) {
|
||||
response.setHeader("Access-Control-Allow-Origin", embedded ? "*" : origin);
|
||||
response.setHeader("Access-Control-Allow-Credentials", "true");
|
||||
response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS");
|
||||
|
@ -148,7 +148,7 @@ public class HttpClientUtil {
|
||||
public static String post(String url, String json, HttpClientConfig config) {
|
||||
CloseableHttpClient httpClient = null;
|
||||
try {
|
||||
buildHttpClient(url);
|
||||
httpClient = buildHttpClient(url);
|
||||
HttpPost httpPost = new HttpPost(url);
|
||||
if (config == null) {
|
||||
config = new HttpClientConfig();
|
||||
|
@ -14,10 +14,13 @@ public class WhitelistUtils {
|
||||
"/dekey",
|
||||
"/index.html",
|
||||
"/model",
|
||||
"/deApi",
|
||||
"/demo.html",
|
||||
"/swagger-resources",
|
||||
"/doc.html",
|
||||
"/panel.html",
|
||||
"/lark/info",
|
||||
"/lark/token",
|
||||
"/setting/authentication/status",
|
||||
"/");
|
||||
|
||||
@ -33,6 +36,7 @@ public class WhitelistUtils {
|
||||
|| StringUtils.startsWithAny(requestURI, "/static-resource/")
|
||||
|| StringUtils.startsWithAny(requestURI, "/share/proxyInfo")
|
||||
|| StringUtils.startsWithAny(requestURI, "/xpackComponent/content/")
|
||||
|| StringUtils.startsWithAny(requestURI, "/platform/")
|
||||
|| StringUtils.startsWithAny(requestURI, "/map/");
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user