forked from github/dataease
refactor: 模版市场UI优化
This commit is contained in:
parent
296c6de279
commit
8d68fb916b
@ -14,18 +14,18 @@ public class MybatisPlusGenerator {
|
||||
* 第一 我嫌麻烦
|
||||
* 第二 后面配置会放到nacos读起来更麻烦了
|
||||
*/
|
||||
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 url = "jdbc:mysql://localhost:3306/dataease?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";
|
||||
private static final String password = "123456";
|
||||
|
||||
/**
|
||||
* 业务模块例如datasource,dataset,panel等
|
||||
*/
|
||||
private static final String busi = "template";
|
||||
private static final String busi = "operation";
|
||||
/**
|
||||
* 这是要生成代码的表名称
|
||||
*/
|
||||
private static final String TABLE_NAME = "visualization_template_extend_data";
|
||||
private static final String TABLE_NAME = "core_opt_recent";
|
||||
|
||||
/**
|
||||
* 下面两个配置基本上不用动
|
||||
|
@ -9,7 +9,7 @@ public class OptConstants {
|
||||
public static final class OPT_TYPE {
|
||||
//新建
|
||||
public static final int NEW = 1;
|
||||
//新建
|
||||
//更新
|
||||
public static final int UPDATE = 2;
|
||||
//删除
|
||||
public static final int DELETE = 3;
|
||||
@ -26,6 +26,8 @@ public class OptConstants {
|
||||
public static final int DATASET = 4;
|
||||
//数据源
|
||||
public static final int DATASOURCE = 5;
|
||||
//模版
|
||||
public static final int TEMPLATE = 6;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ import java.io.Serializable;
|
||||
* </p>
|
||||
*
|
||||
* @author fit2cloud
|
||||
* @since 2023-10-08
|
||||
* @since 2023-11-26
|
||||
*/
|
||||
@TableName("core_opt_recent")
|
||||
public class CoreOptRecent implements Serializable {
|
||||
@ -26,6 +26,11 @@ public class CoreOptRecent implements Serializable {
|
||||
*/
|
||||
private Long resourceId;
|
||||
|
||||
/**
|
||||
* 资源名称
|
||||
*/
|
||||
private String resourceName;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
@ -62,6 +67,14 @@ public class CoreOptRecent implements Serializable {
|
||||
this.resourceId = resourceId;
|
||||
}
|
||||
|
||||
public String getResourceName() {
|
||||
return resourceName;
|
||||
}
|
||||
|
||||
public void setResourceName(String resourceName) {
|
||||
this.resourceName = resourceName;
|
||||
}
|
||||
|
||||
public Long getUid() {
|
||||
return uid;
|
||||
}
|
||||
@ -99,6 +112,7 @@ public class CoreOptRecent implements Serializable {
|
||||
return "CoreOptRecent{" +
|
||||
"id = " + id +
|
||||
", resourceId = " + resourceId +
|
||||
", resourceName = " + resourceName +
|
||||
", uid = " + uid +
|
||||
", resourceType = " + resourceType +
|
||||
", optType = " + optType +
|
||||
|
@ -10,7 +10,7 @@ import org.apache.ibatis.annotations.Mapper;
|
||||
* </p>
|
||||
*
|
||||
* @author fit2cloud
|
||||
* @since 2023-10-08
|
||||
* @since 2023-11-26
|
||||
*/
|
||||
@Mapper
|
||||
public interface CoreOptRecentMapper extends BaseMapper<CoreOptRecent> {
|
||||
|
@ -1,13 +1,21 @@
|
||||
package io.dataease.operation.manage;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import io.dataease.commons.constants.OptConstants;
|
||||
import io.dataease.operation.dao.auto.entity.CoreOptRecent;
|
||||
import io.dataease.operation.dao.auto.mapper.CoreOptRecentMapper;
|
||||
import io.dataease.utils.AuthUtils;
|
||||
import io.dataease.utils.IDUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
||||
@Component
|
||||
public class CoreOptRecentManage {
|
||||
@ -15,19 +23,33 @@ public class CoreOptRecentManage {
|
||||
@Autowired
|
||||
private CoreOptRecentMapper coreStoreMapper;
|
||||
|
||||
public void saveOpt(Long resourceId,int resourceType,int optType) {
|
||||
public void saveOpt(Long resourceId, int resourceType, int optType) {
|
||||
saveOpt(resourceId, null, resourceType, optType);
|
||||
}
|
||||
|
||||
public void saveOpt(String resourceName, int resourceType, int optType) {
|
||||
saveOpt(null, resourceName, resourceType, optType);
|
||||
}
|
||||
|
||||
public void saveOpt(Long resourceId, String resourceName, int resourceType, int optType) {
|
||||
Long uid = AuthUtils.getUser().getUserId();
|
||||
QueryWrapper<CoreOptRecent> updateWrapper = new QueryWrapper<>();
|
||||
updateWrapper.eq("resource_id",resourceId);
|
||||
updateWrapper.eq("resource_type",resourceType);
|
||||
updateWrapper.eq("uid",uid);
|
||||
if (resourceId != null) {
|
||||
updateWrapper.eq("resource_id", resourceId);
|
||||
}
|
||||
if (StringUtils.isNotEmpty(resourceName)) {
|
||||
updateWrapper.eq("resource_name", resourceName);
|
||||
}
|
||||
updateWrapper.eq("resource_type", resourceType);
|
||||
updateWrapper.eq("uid", uid);
|
||||
CoreOptRecent updateParam = new CoreOptRecent();
|
||||
updateParam.setOptType(optType);
|
||||
updateParam.setTime(System.currentTimeMillis());
|
||||
if(coreStoreMapper.update(updateParam,updateWrapper)==0){
|
||||
if (coreStoreMapper.update(updateParam, updateWrapper) == 0) {
|
||||
CoreOptRecent optRecent = new CoreOptRecent();
|
||||
optRecent.setId(IDUtils.snowID());
|
||||
optRecent.setResourceId(resourceId);
|
||||
optRecent.setResourceName(resourceName);
|
||||
optRecent.setResourceType(resourceType);
|
||||
optRecent.setOptType(optType);
|
||||
optRecent.setTime(System.currentTimeMillis());
|
||||
@ -36,4 +58,17 @@ public class CoreOptRecentManage {
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String, Long> findTemplateRecentUseTime() {
|
||||
Long uid = AuthUtils.getUser().getUserId();
|
||||
QueryWrapper<CoreOptRecent> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("resource_type", OptConstants.OPT_RESOURCE_TYPE.TEMPLATE);
|
||||
queryWrapper.eq("uid", uid);
|
||||
List<CoreOptRecent> result = coreStoreMapper.selectList(queryWrapper);
|
||||
if (CollectionUtil.isNotEmpty(result)) {
|
||||
return result.stream().collect(Collectors.toMap(CoreOptRecent::getResourceName, CoreOptRecent::getTime));
|
||||
} else {
|
||||
return new HashMap<>();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2,11 +2,13 @@ package io.dataease.template.manage;
|
||||
|
||||
import io.dataease.api.template.dto.TemplateManageFileDTO;
|
||||
import io.dataease.api.template.dto.TemplateMarketDTO;
|
||||
import io.dataease.api.template.dto.TemplateMarketPreviewInfoDTO;
|
||||
import io.dataease.api.template.response.*;
|
||||
import io.dataease.api.template.vo.MarketApplicationSpecVO;
|
||||
import io.dataease.api.template.vo.MarketMetaDataVO;
|
||||
import io.dataease.api.template.vo.TemplateCategoryVO;
|
||||
import io.dataease.exception.DEException;
|
||||
import io.dataease.operation.manage.CoreOptRecentManage;
|
||||
import io.dataease.system.manage.SysParameterManage;
|
||||
import io.dataease.utils.HttpClientConfig;
|
||||
import io.dataease.utils.HttpClientUtil;
|
||||
@ -16,10 +18,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;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@ -38,6 +37,9 @@ public class TemplateMarketManage {
|
||||
@Resource
|
||||
private SysParameterManage sysParameterManage;
|
||||
|
||||
@Resource
|
||||
private CoreOptRecentManage coreOptRecentManage;
|
||||
|
||||
/**
|
||||
* @param templateUrl template url
|
||||
* @Description Get template file from template market
|
||||
@ -62,26 +64,91 @@ public class TemplateMarketManage {
|
||||
return HttpClientUtil.get(url, config);
|
||||
}
|
||||
|
||||
private MarketTemplateV2BaseResponse templateQuery(Map<String, String> templateParams){
|
||||
String result = marketGet(templateParams.get("template.url") + POSTS_API_V2, null);
|
||||
MarketTemplateV2BaseResponse postsResult = JsonUtil.parseObject(result, MarketTemplateV2BaseResponse.class);
|
||||
return postsResult;
|
||||
}
|
||||
|
||||
public MarketBaseResponse searchTemplate() {
|
||||
try {
|
||||
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"));
|
||||
return baseResponseV2Trans(templateQuery(templateParams), templateParams.get("template.url"));
|
||||
} catch (Exception e) {
|
||||
DEException.throwException(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private MarketBaseResponse baseResponseV2Trans(MarketTemplateV2BaseResponse v2BaseResponse, String url) {
|
||||
public MarketBaseResponse searchTemplateRecommend() {
|
||||
try {
|
||||
Map<String, String> templateParams = sysParameterManage.groupVal("template.");
|
||||
return baseResponseV2TransRecommend(templateQuery(templateParams), templateParams.get("template.url"));
|
||||
} catch (Exception e) {
|
||||
DEException.throwException(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public MarketPreviewBaseResponse searchTemplatePreview() {
|
||||
try {
|
||||
Map<String, String> templateParams = sysParameterManage.groupVal("template.");
|
||||
return basePreviewResponseV2Trans(templateQuery(templateParams), templateParams.get("template.url"));
|
||||
} catch (Exception e) {
|
||||
DEException.throwException(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private MarketBaseResponse baseResponseV2TransRecommend(MarketTemplateV2BaseResponse v2BaseResponse, String url) {
|
||||
Map<String, Long> useTime = coreOptRecentManage.findTemplateRecentUseTime();
|
||||
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())));
|
||||
if("Y".equalsIgnoreCase(spec.getSuggest())){
|
||||
contents.add(new TemplateMarketDTO(spec.getReadmeName(), spec.getDisplayName(), spec.getScreenshots().get(0).getUrl(), spec.getLinks().get(0).getUrl(), categoriesMap.get(spec.getLabel()), spec.getTemplateType(), useTime.get(spec.getReadmeName()),"Y"));
|
||||
}
|
||||
});
|
||||
return new MarketBaseResponse(url, contents);
|
||||
// 最近使用排序
|
||||
Collections.sort(contents);
|
||||
return new MarketBaseResponse(url,contents);
|
||||
}
|
||||
|
||||
private MarketBaseResponse baseResponseV2Trans(MarketTemplateV2BaseResponse v2BaseResponse, String url) {
|
||||
Map<String, Long> useTime = coreOptRecentManage.findTemplateRecentUseTime();
|
||||
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()), spec.getTemplateType(), useTime.get(spec.getReadmeName()),spec.getSuggest()));
|
||||
});
|
||||
// 最近使用排序
|
||||
Collections.sort(contents);
|
||||
return new MarketBaseResponse(url,contents);
|
||||
}
|
||||
|
||||
private MarketPreviewBaseResponse basePreviewResponseV2Trans(MarketTemplateV2BaseResponse v2BaseResponse, String url) {
|
||||
Map<String, Long> useTime = coreOptRecentManage.findTemplateRecentUseTime();
|
||||
Map<String, String> categoriesMap = getCategoriesBaseV2();
|
||||
List<String> categories = new ArrayList<>();
|
||||
List<TemplateMarketPreviewInfoDTO> result = new ArrayList<>();
|
||||
categoriesMap.forEach((key,value)->{
|
||||
if(!"全部".equalsIgnoreCase(value)){
|
||||
categories.add(value);
|
||||
List<TemplateMarketDTO> contents = new ArrayList<>();
|
||||
v2BaseResponse.getItems().stream().forEach(marketTemplateV2ItemResult -> {
|
||||
MarketApplicationSpecVO spec = marketTemplateV2ItemResult.getApplication().getSpec();
|
||||
if(key.equalsIgnoreCase(spec.getLabel())){
|
||||
contents.add(new TemplateMarketDTO(spec.getReadmeName(), spec.getDisplayName(), spec.getScreenshots().get(0).getUrl(), spec.getLinks().get(0).getUrl(), categoriesMap.get(spec.getLabel()), spec.getTemplateType(), useTime.get(spec.getReadmeName()),spec.getSuggest()));
|
||||
}
|
||||
});
|
||||
Collections.sort(contents);
|
||||
result.add(new TemplateMarketPreviewInfoDTO(value,contents));
|
||||
}
|
||||
});
|
||||
// 最近使用排序
|
||||
return new MarketPreviewBaseResponse(url,categories,result);
|
||||
}
|
||||
|
||||
public MarketBaseResponse searchTemplateV1() {
|
||||
@ -115,6 +182,13 @@ public class TemplateMarketManage {
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public List<MarketMetaDataVO> getCategoriesObject() {
|
||||
List<MarketMetaDataVO> result = getCategoriesV2();
|
||||
result.add(0, new MarketMetaDataVO("suggest", "推荐"));
|
||||
result.add(0, new MarketMetaDataVO("recent", "最近使用"));
|
||||
return result;
|
||||
}
|
||||
|
||||
public Map<String, String> getCategoriesBaseV2() {
|
||||
Map<String, String> categories = getCategoriesV2().stream()
|
||||
.collect(Collectors.toMap(MarketMetaDataVO::getSlug, MarketMetaDataVO::getLabel));
|
||||
|
@ -2,6 +2,8 @@ package io.dataease.template.service;
|
||||
|
||||
import io.dataease.api.template.TemplateMarketApi;
|
||||
import io.dataease.api.template.response.MarketBaseResponse;
|
||||
import io.dataease.api.template.response.MarketPreviewBaseResponse;
|
||||
import io.dataease.api.template.vo.MarketMetaDataVO;
|
||||
import io.dataease.template.manage.TemplateMarketManage;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@ -23,9 +25,23 @@ public class TemplateMarketService implements TemplateMarketApi {
|
||||
public MarketBaseResponse searchTemplate() {
|
||||
return templateMarketManage.searchTemplate();
|
||||
}
|
||||
@Override
|
||||
public MarketBaseResponse searchTemplateRecommend() {
|
||||
return templateMarketManage.searchTemplateRecommend();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MarketPreviewBaseResponse searchTemplatePreview() {
|
||||
return templateMarketManage.searchTemplatePreview();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> categories() {
|
||||
return templateMarketManage.getCategories();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MarketMetaDataVO> categoriesObject() {
|
||||
return templateMarketManage.getCategoriesObject();
|
||||
}
|
||||
}
|
||||
|
@ -15,11 +15,13 @@ 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.commons.constants.OptConstants;
|
||||
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.operation.manage.CoreOptRecentManage;
|
||||
import io.dataease.template.dao.auto.entity.VisualizationTemplate;
|
||||
import io.dataease.template.dao.auto.entity.VisualizationTemplateExtendData;
|
||||
import io.dataease.template.dao.auto.mapper.VisualizationTemplateExtendDataMapper;
|
||||
@ -79,6 +81,8 @@ public class DataVisualizationServer implements DataVisualizationApi {
|
||||
@Resource
|
||||
private VisualizationTemplateExtendDataMapper templateExtendDataMapper;
|
||||
|
||||
@Resource
|
||||
private CoreOptRecentManage coreOptRecentManage;
|
||||
|
||||
@Override
|
||||
@XpackInteract(value = "dataVisualizationServer", original = true)
|
||||
@ -257,6 +261,8 @@ public class DataVisualizationServer implements DataVisualizationApi {
|
||||
staticResource = templateFileInfo.getStaticResource();
|
||||
name = templateFileInfo.getName();
|
||||
dvType = templateFileInfo.getDvType();
|
||||
// 模版市场记录
|
||||
coreOptRecentManage.saveOpt(request.getResourceName(), OptConstants.OPT_RESOURCE_TYPE.TEMPLATE,OptConstants.OPT_TYPE.NEW);
|
||||
}
|
||||
// 解析动态数据
|
||||
Map<String, String> dynamicDataMap = JsonUtil.parseObject(dynamicData, Map.class);
|
||||
|
@ -18,7 +18,7 @@ CREATE TABLE `visualization_template` (
|
||||
|
||||
BEGIN;
|
||||
INSERT INTO `core_menu`
|
||||
VALUES (19, 0, 2, 'template-market', 'template-market', 4, NULL, '/template-market', 0, 1, 0);
|
||||
VALUES (19, 0, 2, 'template-market', 'template-market', 4, NULL, '/template-market', 0, 1, 1);
|
||||
INSERT INTO `core_menu`
|
||||
VALUES (20, 15, 2, 'template-setting', 'system/template-setting', 4, 'icon_template', '/template-setting', 0, 1, 1);
|
||||
COMMIT;
|
||||
@ -33,3 +33,7 @@ CREATE TABLE `visualization_template_extend_data` (
|
||||
`copy_id` varchar(255) DEFAULT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
);
|
||||
|
||||
ALTER TABLE `core_opt_recent`
|
||||
MODIFY COLUMN `resource_id` bigint NULL COMMENT '资源ID' AFTER `id`,
|
||||
ADD COLUMN `resource_name` varchar(255) NULL COMMENT '资源名称' AFTER `resource_id`;
|
@ -20,7 +20,7 @@ CREATE TABLE `visualization_template`
|
||||
|
||||
BEGIN;
|
||||
INSERT INTO `core_menu`
|
||||
VALUES (19, 0, 2, 'template-market', 'template-market', 4, NULL, '/template-market', 0, 1, 0);
|
||||
VALUES (19, 0, 2, 'template-market', 'template-market', 4, NULL, '/template-market', 0, 1, 1);
|
||||
INSERT INTO `core_menu`
|
||||
VALUES (20, 15, 2, 'template-setting', 'system/template-setting', 4, 'icon_template', '/template-setting', 0, 1, 1);
|
||||
COMMIT;
|
||||
@ -35,3 +35,8 @@ CREATE TABLE `visualization_template_extend_data` (
|
||||
`copy_id` varchar(255) DEFAULT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
);
|
||||
|
||||
|
||||
ALTER TABLE `core_opt_recent`
|
||||
MODIFY COLUMN `resource_id` bigint NULL COMMENT '资源ID' AFTER `id`,
|
||||
ADD COLUMN `resource_name` varchar(255) NULL COMMENT '资源名称' AFTER `resource_id`;
|
@ -6,8 +6,26 @@ export function searchMarket() {
|
||||
})
|
||||
}
|
||||
|
||||
export function searchMarketRecommend() {
|
||||
return request.get({
|
||||
url: '/templateMarket/searchRecommend'
|
||||
})
|
||||
}
|
||||
|
||||
export function searchMarketPreview() {
|
||||
return request.get({
|
||||
url: '/templateMarket/searchPreview'
|
||||
})
|
||||
}
|
||||
|
||||
export function getCategories() {
|
||||
return request.get({
|
||||
url: '/templateMarket/categories'
|
||||
})
|
||||
}
|
||||
|
||||
export function getCategoriesObject() {
|
||||
return request.get({
|
||||
url: '/templateMarket/categoriesObject'
|
||||
})
|
||||
}
|
||||
|
31
core/core-frontend/src/assets/svg/market-expand.svg
Normal file
31
core/core-frontend/src/assets/svg/market-expand.svg
Normal file
@ -0,0 +1,31 @@
|
||||
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g filter="url(#filter0_d_2346_358803)">
|
||||
<path d="M8 4H20C26.6274 4 32 9.37258 32 16C32 22.6274 26.6274 28 20 28H8V4Z" fill="white"/>
|
||||
</g>
|
||||
<g filter="url(#filter1_d_2346_358803)">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M20 5H8V27H20C26.0751 27 31 22.0751 31 16C31 9.92487 26.0751 5 20 5ZM8 4V28H20C26.6274 28 32 22.6274 32 16C32 9.37258 26.6274 4 20 4H8Z" fill="#DEE0E3"/>
|
||||
</g>
|
||||
<path d="M20.1391 16.0005L16.0732 20.0663C15.9756 20.164 15.9756 20.3223 16.0732 20.4199L16.4268 20.7735C16.5244 20.8711 16.6827 20.8711 16.7803 20.7735L21.1997 16.354C21.395 16.1588 21.395 15.8422 21.1997 15.6469L16.7803 11.2275C16.6827 11.1299 16.5244 11.1299 16.4268 11.2275L16.0732 11.5811C15.9756 11.6787 15.9756 11.837 16.0732 11.9346L20.1391 16.0005Z" fill="#3370FF"/>
|
||||
<defs>
|
||||
<filter id="filter0_d_2346_358803" x="0" y="0" width="40" height="40" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||
<feOffset dy="4"/>
|
||||
<feGaussianBlur stdDeviation="4"/>
|
||||
<feComposite in2="hardAlpha" operator="out"/>
|
||||
<feColorMatrix type="matrix" values="0 0 0 0 0.121569 0 0 0 0 0.137255 0 0 0 0 0.160784 0 0 0 0.1 0"/>
|
||||
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_2346_358803"/>
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_2346_358803" result="shape"/>
|
||||
</filter>
|
||||
<filter id="filter1_d_2346_358803" x="0" y="0" width="40" height="40" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||
<feOffset dy="4"/>
|
||||
<feGaussianBlur stdDeviation="4"/>
|
||||
<feComposite in2="hardAlpha" operator="out"/>
|
||||
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0"/>
|
||||
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_2346_358803"/>
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_2346_358803" result="shape"/>
|
||||
</filter>
|
||||
</defs>
|
||||
</svg>
|
After Width: | Height: | Size: 2.2 KiB |
19
core/core-frontend/src/assets/svg/market-retract.svg
Normal file
19
core/core-frontend/src/assets/svg/market-retract.svg
Normal file
@ -0,0 +1,19 @@
|
||||
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g filter="url(#filter0_d_2356_358817)">
|
||||
<rect width="24" height="24" rx="12" transform="matrix(-1 0 0 1 32 4)" fill="white"/>
|
||||
<rect x="-0.5" y="0.5" width="23" height="23" rx="11.5" transform="matrix(-1 0 0 1 31 4)" stroke="#DEE0E3"/>
|
||||
</g>
|
||||
<path d="M17.8181 16.0005L21.8839 11.9346C21.9816 11.837 21.9816 11.6787 21.8839 11.5811L21.5304 11.2275C21.4327 11.1299 21.2745 11.1299 21.1768 11.2275L16.7574 15.6469C16.5621 15.8422 16.5621 16.1588 16.7574 16.354L21.1768 20.7735C21.2745 20.8711 21.4327 20.8711 21.5304 20.7735L21.8839 20.4199C21.9816 20.3223 21.9816 20.164 21.8839 20.0663L17.8181 16.0005Z" fill="#1F2329"/>
|
||||
<defs>
|
||||
<filter id="filter0_d_2356_358817" x="0" y="0" width="40" height="40" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||
<feOffset dy="4"/>
|
||||
<feGaussianBlur stdDeviation="4"/>
|
||||
<feComposite in2="hardAlpha" operator="out"/>
|
||||
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0"/>
|
||||
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_2356_358817"/>
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_2356_358817" result="shape"/>
|
||||
</filter>
|
||||
</defs>
|
||||
</svg>
|
After Width: | Height: | Size: 1.4 KiB |
@ -1,5 +1,14 @@
|
||||
<svg width="125" height="125" viewBox="0 0 125 125" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="125" height="125" rx="62.5" fill="#EBEBEB"/>
|
||||
<path d="M82.625 48.1813H71.125V36.6252H42.375V88.3752H56.75V94.1252H39.5C38.7375 94.1252 38.0062 93.8223 37.4671 93.2831C36.9279 92.744 36.625 92.0127 36.625 91.2502V33.7502C36.625 32.9877 36.9279 32.2564 37.4671 31.7173C38.0062 31.1781 38.7375 30.8752 39.5 30.8752H75.4375L88.375 44.4294V56.7502H82.625V48.1813Z" fill="#BBBFC4"/>
|
||||
<path d="M75.4375 91.25C78.4004 91.25 81.154 90.3536 83.4417 88.8172L88.8204 94.1958C89.3817 94.7572 90.2919 94.7572 90.8533 94.1958L93.2928 91.7563C93.8542 91.1949 93.8542 90.2847 93.2928 89.7233L87.7941 84.2247C89.0761 82.0741 89.8125 79.5605 89.8125 76.875C89.8125 68.9359 83.3766 62.5 75.4375 62.5C67.4984 62.5 61.0625 68.9359 61.0625 76.875C61.0625 84.8141 67.4984 91.25 75.4375 91.25ZM84.0625 76.875C84.0625 81.6384 80.201 85.5 75.4375 85.5C70.674 85.5 66.8125 81.6384 66.8125 76.875C66.8125 72.1115 70.674 68.25 75.4375 68.25C80.201 68.25 84.0625 72.1115 84.0625 76.875Z" fill="#BBBFC4"/>
|
||||
<svg width="80" height="80" viewBox="0 0 80 80" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M19.0705 8.95996H65.4094C67.4587 8.95996 69.12 10.6118 69.12 12.6494V53.7236L53.296 70.0591H19.0705C17.0213 70.0591 15.36 68.4073 15.36 66.3697V12.6494C15.36 10.6118 17.0213 8.95996 19.0705 8.95996Z" fill="#D6DAE1"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M53.2959 70.0327V54.9271C53.2959 54.2479 53.8497 53.6973 54.5328 53.6973H69.1199L53.2959 70.0327Z" fill="#B5BEC8"/>
|
||||
<rect x="48.4399" y="14.0796" width="16" height="20.48" rx="2" fill="#F4F5F9"/>
|
||||
<rect x="20.2241" y="14.1152" width="20.64" height="3.2" rx="1" fill="#F4F5F9"/>
|
||||
<rect x="20.2241" y="20.2505" width="20.64" height="3.2" rx="1" fill="#F4F5F9"/>
|
||||
<rect x="20.2241" y="26.6504" width="10.32" height="3.2" rx="1" fill="#F4F5F9"/>
|
||||
<rect x="20.2241" y="44.1108" width="44.032" height="3.2" rx="1" fill="#F4F5F9"/>
|
||||
<rect x="20.2241" y="48.8833" width="44.032" height="3.2" rx="1" fill="#F4F5F9"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M31.8181 34.6489C24.496 34.6489 18.5602 40.6141 18.5602 47.9725C18.5602 55.3309 24.496 61.296 31.8181 61.296C33.6008 61.296 35.3013 60.9425 36.8539 60.3013L43.7463 70.637L47.2995 68.2432L40.4981 58.0439C43.3024 55.6009 45.0761 51.9949 45.0761 47.9725C45.0761 40.6141 39.1403 34.6489 31.8181 34.6489ZM31.8181 38.9472C36.7782 38.9472 40.7993 42.9881 40.7993 47.9728C40.7993 52.9575 36.7782 56.9985 31.8181 56.9985C26.8579 56.9985 22.8369 52.9575 22.8369 47.9728C22.8369 42.9881 26.8579 38.9472 31.8181 38.9472Z" fill="white"/>
|
||||
<path d="M15.7495 38.3938L15.4811 39.0205L9.58404 36.4913L9.85248 35.8646L15.7495 38.3938Z" fill="#1F2329"/>
|
||||
<path d="M18.9606 36.2086L18.4367 36.6449L13.3637 30.5493L13.8876 30.113L18.9606 36.2086Z" fill="#1F2329"/>
|
||||
<path d="M15.8575 42.0183L15.882 42.7005L7.80575 42.9754L7.78133 42.2932L15.8575 42.0183Z" fill="#1F2329"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.9 KiB |
@ -0,0 +1,94 @@
|
||||
<script lang="ts" setup>
|
||||
import { ElHeader } from 'element-plus-secondary'
|
||||
import { useRouter } from 'vue-router'
|
||||
import AccountOperator from '@/layout/components/AccountOperator.vue'
|
||||
const { push } = useRouter()
|
||||
const backToMain = () => {
|
||||
push('/workbranch/index')
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-header class="header-flex system-header">
|
||||
<Icon className="logo" name="logo"></Icon>
|
||||
<el-divider direction="vertical" />
|
||||
<span class="system">模版市场</span>
|
||||
<div class="operate-setting">
|
||||
<span @click="backToMain" class="work-bar flex-align-center">
|
||||
<el-icon>
|
||||
<Icon name="icon_left_outlined"></Icon>
|
||||
</el-icon>
|
||||
<span class="work">返回工作台</span>
|
||||
</span>
|
||||
|
||||
<AccountOperator />
|
||||
</div>
|
||||
</el-header>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.system-header {
|
||||
font-family: PingFang SC;
|
||||
|
||||
.logo {
|
||||
width: 134px;
|
||||
height: 34px;
|
||||
}
|
||||
|
||||
.ed-divider {
|
||||
margin: 0 24px;
|
||||
border-color: rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
.system {
|
||||
color: #fff;
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
.work-bar {
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 22px;
|
||||
cursor: pointer;
|
||||
.ed-icon {
|
||||
margin-right: 4px;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.avatar {
|
||||
margin: 0 -7px 0 20px !important;
|
||||
}
|
||||
}
|
||||
.header-flex {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 56px;
|
||||
background-color: #050e21;
|
||||
padding: 0 24px;
|
||||
.operate-setting {
|
||||
margin-left: auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="less">
|
||||
.header-flex {
|
||||
.operate-setting {
|
||||
.ed-icon {
|
||||
cursor: pointer;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -7,14 +7,17 @@ import Menu from './components/Menu.vue'
|
||||
import Main from './components/Main.vue'
|
||||
import { ElContainer } from 'element-plus-secondary'
|
||||
import { useRoute } from 'vue-router'
|
||||
import HeaderTemplateMarket from '@/layout/components/HeaderTemplateMarket.vue'
|
||||
const route = useRoute()
|
||||
const systemMenu = computed(() => route.path.includes('system'))
|
||||
const settingMenu = computed(() => route.path.includes('sys-setting'))
|
||||
const templateMarketMenu = computed(() => route.path.includes('template-market'))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="common-layout">
|
||||
<HeaderSystem v-if="settingMenu"></HeaderSystem>
|
||||
<header-template-market v-if="templateMarketMenu"></header-template-market>
|
||||
<HeaderSystem v-else-if="settingMenu"></HeaderSystem>
|
||||
<Header v-else></Header>
|
||||
<el-container class="layout-container">
|
||||
<Sidebar v-if="systemMenu || settingMenu" class="layout-sidebar">
|
||||
|
@ -147,12 +147,19 @@ watch(
|
||||
}
|
||||
)
|
||||
|
||||
const initMarketTemplate = () => {
|
||||
searchMarket()
|
||||
const initMarketTemplate = async () => {
|
||||
await searchMarket()
|
||||
.then(rsp => {
|
||||
state.baseUrl = rsp.data.baseUrl
|
||||
state.currentMarketTemplateShowList = rsp.data.contents
|
||||
state.hasResult = true
|
||||
if (props.previewId) {
|
||||
state.currentMarketTemplateShowList.forEach(template => {
|
||||
if (props.previewId === template.id) {
|
||||
previewTemplate(template)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
state.networkStatus = false
|
||||
@ -165,17 +172,6 @@ const initMarketTemplate = () => {
|
||||
.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 => {
|
||||
@ -248,7 +244,6 @@ const active = template => {
|
||||
|
||||
onMounted(() => {
|
||||
initMarketTemplate()
|
||||
getGroupTree()
|
||||
})
|
||||
</script>
|
||||
|
||||
|
@ -0,0 +1,579 @@
|
||||
<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-tooltip class="box-item" effect="dark" content="展开" placement="right">
|
||||
<el-icon v-show="!state.asideActive" class="insert" @click="asideActiveChange(true)">
|
||||
<Icon name="market-expand"></Icon>
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
<el-row v-show="state.asideActive" style="padding: 24px 12px 0">
|
||||
<el-row style="align-items: center">
|
||||
<el-breadcrumb separator-icon="ArrowRight">
|
||||
<el-breadcrumb-item class="custom-breadcrumb-item" @click="closePreview()">{{
|
||||
t('visualization.template_preview')
|
||||
}}</el-breadcrumb-item>
|
||||
<el-breadcrumb-item>预览</el-breadcrumb-item>
|
||||
</el-breadcrumb>
|
||||
<el-tooltip class="box-item" effect="dark" content="收起" placement="right">
|
||||
<el-icon class="insert-retract" @click="asideActiveChange(false)">
|
||||
<Icon name="market-retract"></Icon>
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</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.templateType"
|
||||
class="margin-top16"
|
||||
size="small"
|
||||
placeholder="请选择"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in state.templateTypeOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-row>
|
||||
<el-divider />
|
||||
</el-row>
|
||||
|
||||
<el-row
|
||||
v-show="state.asideActive"
|
||||
class="aside-list"
|
||||
:class="state.extFilterActive ? 'aside-list-filter-active' : ''"
|
||||
>
|
||||
<el-collapse v-show="state.hasResult" v-model="activeCategories" class="market-collapse">
|
||||
<el-collapse-item
|
||||
themes="light"
|
||||
v-for="(categoryTemplate, index) in state.marketTemplatePreviewShowList"
|
||||
:name="categoryTemplate['categoryType']"
|
||||
:key="index"
|
||||
:title="categoryTemplate['categoryType']"
|
||||
>
|
||||
<template-market-preview-item
|
||||
v-for="templateItem in categoryTemplate['contents']"
|
||||
v-show="templateItem.showFlag"
|
||||
:key="templateItem.id"
|
||||
:template="templateItem"
|
||||
:base-url="state.baseUrl"
|
||||
:active="active(templateItem)"
|
||||
@previewTemplate="previewTemplate"
|
||||
/>
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
<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>没有找到相关模版</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 { searchMarketPreview } from '@/api/templateMarket'
|
||||
import { onMounted, reactive, watch, ref } from 'vue'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import TemplateMarketPreviewItem from '@/views/template-market/component/TemplateMarketPreviewItem.vue'
|
||||
import { deepCopy } from '@/utils/utils'
|
||||
const { t } = useI18n()
|
||||
|
||||
const props = defineProps({
|
||||
previewId: {
|
||||
type: String,
|
||||
default: null
|
||||
}
|
||||
})
|
||||
|
||||
const emits = defineEmits(['templateApply', 'closeDialog', 'closePreview'])
|
||||
const activeCategories = ref([])
|
||||
|
||||
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',
|
||||
marketTemplatePreviewShowList: [],
|
||||
categories: [],
|
||||
networkStatus: true,
|
||||
curTemplate: null,
|
||||
templateType: 'all',
|
||||
templateTypeOptions: [
|
||||
{
|
||||
value: 'all',
|
||||
label: '全部类型'
|
||||
},
|
||||
{
|
||||
value: 'PANEL',
|
||||
label: '仪表板'
|
||||
},
|
||||
{
|
||||
value: 'SCREEN',
|
||||
label: '大屏'
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
watch(
|
||||
() => state.templateType,
|
||||
value => {
|
||||
initTemplateShow()
|
||||
}
|
||||
)
|
||||
|
||||
watch(
|
||||
() => state.searchText,
|
||||
value => {
|
||||
initTemplateShow()
|
||||
}
|
||||
)
|
||||
|
||||
watch(
|
||||
() => props.previewId,
|
||||
value => {
|
||||
state.marketTemplatePreviewShowList.forEach(categoryTemplates => {
|
||||
categoryTemplates.contents.forEach(template => {
|
||||
if (props.previewId === template.id) {
|
||||
previewTemplate(template)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
const initMarketTemplate = () => {
|
||||
searchMarketPreview()
|
||||
.then(rsp => {
|
||||
state.baseUrl = rsp.data.baseUrl
|
||||
state.marketTemplatePreviewShowList = rsp.data.contents
|
||||
state.hasResult = true
|
||||
state.categories = rsp.data.categories
|
||||
activeCategories.value = deepCopy(state.categories)
|
||||
if (props.previewId) {
|
||||
state.marketTemplatePreviewShowList.forEach(categoryTemplates => {
|
||||
categoryTemplates.contents.forEach(template => {
|
||||
if (props.previewId === template.id) {
|
||||
previewTemplate(template)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
state.networkStatus = false
|
||||
})
|
||||
}
|
||||
|
||||
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.marketTemplatePreviewShowList.forEach(categoryTemplates => {
|
||||
categoryTemplates.contents.forEach(template => {
|
||||
template.showFlag = templateShow(template)
|
||||
if (template.showFlag) {
|
||||
state.hasResult = true
|
||||
}
|
||||
})
|
||||
})
|
||||
activeCategories.value = deepCopy(state.categories)
|
||||
}
|
||||
|
||||
const templateShow = templateItem => {
|
||||
let templateTypeMarch = false
|
||||
let searchMarch = false
|
||||
if (state.templateType === 'all' || templateItem.templateType === state.templateType) {
|
||||
templateTypeMarch = true
|
||||
}
|
||||
if (!state.searchText || templateItem.title.indexOf(state.searchText) > -1) {
|
||||
searchMarch = true
|
||||
}
|
||||
return templateTypeMarch && 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()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.market-collapse {
|
||||
width: 100%;
|
||||
border: 0;
|
||||
::v-deep(.ed-collapse-item__content) {
|
||||
padding: 8px 0;
|
||||
border: 0;
|
||||
}
|
||||
::v-deep(.ed-collapse-item__header) {
|
||||
border: 0;
|
||||
}
|
||||
::v-deep(.ed-collapse-item__wrap) {
|
||||
border: 0;
|
||||
background-color: rgba(245, 246, 247, 1);
|
||||
}
|
||||
}
|
||||
.aside-list {
|
||||
padding: 0px 12px 12px 12px;
|
||||
width: 100%;
|
||||
height: calc(100vh - 200px);
|
||||
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;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.aside-active {
|
||||
width: 206px;
|
||||
height: calc(100vh - 56px);
|
||||
background-color: rgba(245, 246, 247, 1);
|
||||
}
|
||||
|
||||
.aside-inActive {
|
||||
position: relative;
|
||||
width: 0px;
|
||||
}
|
||||
|
||||
.main-area-active {
|
||||
width: calc(100% - 206px) !important;
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.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-retract {
|
||||
position: absolute;
|
||||
left: 176px;
|
||||
top: 2px;
|
||||
display: inline-block;
|
||||
font-size: 34px;
|
||||
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;
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: #3a8ee6;
|
||||
}
|
||||
}
|
||||
|
||||
.insert {
|
||||
font-size: 34px;
|
||||
margin-top: 24px;
|
||||
margin-left: -8px;
|
||||
display: inline-block;
|
||||
font-weight: 400 !important;
|
||||
cursor: pointer;
|
||||
color: #646a73;
|
||||
transition: 0.1s;
|
||||
&:active {
|
||||
color: #000;
|
||||
border-color: #3a8ee6;
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
margin-left: -6px;
|
||||
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;
|
||||
}
|
||||
|
||||
.custom-breadcrumb-item {
|
||||
cursor: pointer;
|
||||
::v-deep(.ed-breadcrumb__inner) {
|
||||
color: rgba(100, 106, 115, 1);
|
||||
}
|
||||
}
|
||||
</style>
|
@ -0,0 +1,130 @@
|
||||
<template>
|
||||
<div class="testcase-template">
|
||||
<div class="template-img" :style="classBackground" @click.stop="templateInnerPreview" />
|
||||
<el-row class="bottom-area"> </el-row>
|
||||
<el-row class="bottom-area-show">
|
||||
<el-row class="demonstration">
|
||||
{{ template.title }}
|
||||
</el-row>
|
||||
<el-row class="template-button">
|
||||
<el-button size="mini" style="width: 100px" @click="templateInnerPreview">{{
|
||||
t('visualization.preview')
|
||||
}}</el-button>
|
||||
<el-button size="mini" style="width: 100px" type="primary" @click="apply">{{
|
||||
t('visualization.apply')
|
||||
}}</el-button>
|
||||
</el-row>
|
||||
</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;
|
||||
border: 1px solid rgba(222, 224, 227, 1);
|
||||
box-sizing: border-box;
|
||||
border-radius: 4px;
|
||||
width: 100%;
|
||||
background: #fff;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.demonstration {
|
||||
height: 34px;
|
||||
font-weight: 500;
|
||||
display: block;
|
||||
font-size: 14px;
|
||||
text-align: left;
|
||||
padding: 8px 12px 4px 12px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
color: var(--TextPrimary, #1f2329);
|
||||
}
|
||||
|
||||
.template-img {
|
||||
background-size: 100% 100%;
|
||||
margin: 4px 4px 0 4px;
|
||||
border-radius: 4px 4px 0 0;
|
||||
}
|
||||
|
||||
.template-button {
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.bottom-area {
|
||||
height: 38px;
|
||||
}
|
||||
|
||||
.bottom-area-show {
|
||||
width: 100%;
|
||||
border-top: 1px solid rgba(222, 224, 227, 1);
|
||||
position: absolute;
|
||||
height: 75px;
|
||||
bottom: -38px;
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.testcase-template:hover ::v-deep(.bottom-area-show) {
|
||||
transition: 0.3s;
|
||||
bottom: 0px;
|
||||
}
|
||||
|
||||
.testcase-template:hover ::v-deep(.template-img) {
|
||||
outline: solid 1px #4b8fdf;
|
||||
color: deepskyblue;
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
@ -1,97 +1,130 @@
|
||||
<template>
|
||||
<el-row class="outer-body" v-loading="state.loading">
|
||||
<!--预览模式-->
|
||||
<market-preview
|
||||
<el-row
|
||||
class="template-outer-body"
|
||||
:class="{ 'template-outer-body-padding': !previewModel }"
|
||||
v-loading="state.loading"
|
||||
>
|
||||
<market-preview-v2
|
||||
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">
|
||||
></market-preview-v2>
|
||||
<el-row v-show="!previewModel" class="main-container">
|
||||
<el-row class="market-head">
|
||||
<span>模版市场 </span>
|
||||
<el-row class="head-right">
|
||||
<el-input
|
||||
class="title-search"
|
||||
v-model="state.searchText"
|
||||
prefix-icon="el-icon-search"
|
||||
prefix-icon="Search"
|
||||
size="small"
|
||||
class="title-right"
|
||||
:placeholder="t('visualization.enter_template_name_tips')"
|
||||
:clearable="true"
|
||||
/>
|
||||
</el-col>
|
||||
<el-select
|
||||
class="title-type"
|
||||
v-model="state.templateType"
|
||||
size="small"
|
||||
placeholder="Select"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in state.templateTypeOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-row>
|
||||
</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-row class="template-area">
|
||||
<div class="template-left">
|
||||
<el-tree
|
||||
menu
|
||||
:data="state.marketTabs"
|
||||
:props="state.treeProps"
|
||||
node-key="label"
|
||||
default-expand-all
|
||||
highlight-current
|
||||
:current-node-key="state.marketActiveTab"
|
||||
@node-click="nodeClick"
|
||||
/>
|
||||
</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') }}
|
||||
<div
|
||||
v-show="state.networkStatus && state.hasResult"
|
||||
id="template-show-area"
|
||||
class="template-right"
|
||||
>
|
||||
<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-v2-item
|
||||
:key="'outer-' + templateItem.id"
|
||||
:template="templateItem"
|
||||
:base-url="state.baseUrl"
|
||||
:width="state.templateCurWidth"
|
||||
@templateApply="templateApply"
|
||||
@templatePreview="templatePreview"
|
||||
/>
|
||||
</el-col>
|
||||
</div>
|
||||
<el-row v-show="state.networkStatus && !state.hasResult" class="template-empty">
|
||||
<div style="text-align: center">
|
||||
<Icon name="no_result" style="margin-bottom: 16px; font-size: 75px"></Icon>
|
||||
<br />
|
||||
<span>没有找到相关模版</span>
|
||||
</div>
|
||||
</el-row>
|
||||
<el-row v-show="!state.networkStatus" class="template-empty">
|
||||
{{ t('visualization.market_network_tips') }}
|
||||
</el-row>
|
||||
</el-row>
|
||||
</el-row>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { getCategories, searchMarket } from '@/api/templateMarket'
|
||||
import { getCategoriesObject, 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'
|
||||
import TemplateMarketV2Item from '@/views/template-market/component/TemplateMarketV2Item.vue'
|
||||
import MarketPreviewV2 from '@/views/template-market/component/MarketPreviewV2.vue'
|
||||
const { t } = useI18n()
|
||||
const { wsCache } = useCache()
|
||||
|
||||
const previewModel = ref(false)
|
||||
|
||||
const state = reactive({
|
||||
treeProps: {
|
||||
value: 'label',
|
||||
label: 'label'
|
||||
},
|
||||
templateType: 'all',
|
||||
templateTypeOptions: [
|
||||
{
|
||||
value: 'all',
|
||||
label: '全部类型'
|
||||
},
|
||||
{
|
||||
value: 'PANEL',
|
||||
label: '仪表板'
|
||||
},
|
||||
{
|
||||
value: 'SCREEN',
|
||||
label: '大屏'
|
||||
}
|
||||
],
|
||||
loading: false,
|
||||
hasResult: true,
|
||||
templateMiniWidth: 330,
|
||||
templateMiniWidth: 270,
|
||||
templateCurWidth: 310,
|
||||
templateSpan: '25%',
|
||||
previewVisible: false,
|
||||
@ -100,6 +133,7 @@ const state = reactive({
|
||||
marketActiveTab: null,
|
||||
searchText: null,
|
||||
dvCreateForm: {
|
||||
resourceName: null,
|
||||
name: null,
|
||||
pid: null,
|
||||
nodeType: 'panel',
|
||||
@ -133,13 +167,6 @@ const state = reactive({
|
||||
}
|
||||
})
|
||||
|
||||
watch(
|
||||
() => state.marketActiveTab,
|
||||
value => {
|
||||
initTemplateShow()
|
||||
}
|
||||
)
|
||||
|
||||
watch(
|
||||
() => state.searchText,
|
||||
value => {
|
||||
@ -147,12 +174,22 @@ watch(
|
||||
}
|
||||
)
|
||||
|
||||
watch(
|
||||
() => state.templateType,
|
||||
value => {
|
||||
initTemplateShow()
|
||||
}
|
||||
)
|
||||
const nodeClick = data => {
|
||||
state.marketActiveTab = data.label
|
||||
initTemplateShow()
|
||||
}
|
||||
const closePreview = () => {
|
||||
previewModel.value = false
|
||||
}
|
||||
|
||||
const initMarketTemplate = () => {
|
||||
searchMarket()
|
||||
const initMarketTemplate = async () => {
|
||||
await searchMarket()
|
||||
.then(rsp => {
|
||||
state.baseUrl = rsp.data.baseUrl
|
||||
state.currentMarketTemplateShowList = rsp.data.contents
|
||||
@ -160,21 +197,28 @@ const initMarketTemplate = () => {
|
||||
.catch(() => {
|
||||
state.networkStatus = false
|
||||
})
|
||||
getCategories()
|
||||
getCategoriesObject()
|
||||
.then(rsp => {
|
||||
state.marketTabs = rsp.data
|
||||
state.marketActiveTab = state.marketTabs[0]
|
||||
state.marketActiveTab = state.marketTabs[0].label
|
||||
initStyle()
|
||||
initTemplateShow()
|
||||
})
|
||||
.catch(() => {
|
||||
state.networkStatus = false
|
||||
})
|
||||
}
|
||||
|
||||
const getGroupTree = () => {
|
||||
// do getGroupTree
|
||||
// groupTree({ nodeType: 'folder' }).then(res => {
|
||||
// state.panelGroupList = res.data
|
||||
// })
|
||||
const initStyle = () => {
|
||||
nextTick(() => {
|
||||
const tree = document.querySelector('.ed-tree')
|
||||
// 创建横线元素
|
||||
const line = document.createElement('hr')
|
||||
line.classList.add('custom-line')
|
||||
|
||||
// 将横线元素插入到第一个选项后面
|
||||
tree.firstElementChild.appendChild(line)
|
||||
})
|
||||
}
|
||||
const normalizer = node => {
|
||||
// 去掉children=null的属性
|
||||
@ -187,6 +231,7 @@ const templateApply = template => {
|
||||
state.curApplyTemplate = template
|
||||
state.dvCreateForm.name = template.title
|
||||
state.dvCreateForm.templateUrl = template.metas.theme_repo
|
||||
state.dvCreateForm.resourceName = template.id
|
||||
apply()
|
||||
}
|
||||
|
||||
@ -231,30 +276,43 @@ const initTemplateShow = () => {
|
||||
const templateShow = templateItem => {
|
||||
let categoryMarch = false
|
||||
let searchMarch = false
|
||||
templateItem.categories.forEach(category => {
|
||||
if (category.name === state.marketActiveTab) {
|
||||
let templateTypeMarch = false
|
||||
if (state.marketActiveTab === '最近使用') {
|
||||
if (templateItem.recentUseTime) {
|
||||
categoryMarch = true
|
||||
}
|
||||
})
|
||||
} else if (state.marketActiveTab === '推荐') {
|
||||
if (templateItem.suggest === 'Y') {
|
||||
categoryMarch = true
|
||||
}
|
||||
} else {
|
||||
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
|
||||
|
||||
if (state.templateType === 'all' || templateItem.templateType === state.templateType) {
|
||||
templateTypeMarch = true
|
||||
}
|
||||
return categoryMarch && searchMarch && templateTypeMarch
|
||||
}
|
||||
|
||||
const templatePreview = previewId => {
|
||||
state.templatePreviewId = previewId
|
||||
previewModel.value = true
|
||||
}
|
||||
const newPanel = () => {
|
||||
// do newPanel
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
previewInit()
|
||||
initMarketTemplate()
|
||||
getGroupTree()
|
||||
const erd = elementResizeDetectorMaker()
|
||||
const templateMainDom = document.getElementById('template-main')
|
||||
const templateMainDom = document.getElementById('template-show-area')
|
||||
// 监听div变动事件
|
||||
if (templateMainDom) {
|
||||
erd.listenTo(templateMainDom, element => {
|
||||
@ -267,116 +325,86 @@ onMounted(() => {
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
const previewInit = () => {
|
||||
const previewId = wsCache.get('template-preview-id')
|
||||
if (previewId) {
|
||||
templatePreview(previewId)
|
||||
wsCache.delete('template-preview-id')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.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 - 190px) !important;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
background-color: var(--ContentBG, #ffffff);
|
||||
}
|
||||
|
||||
.market-main {
|
||||
.template-outer-body-padding {
|
||||
padding: 24px;
|
||||
display: inherit;
|
||||
}
|
||||
.template-outer-body {
|
||||
.main-container {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
.market-head {
|
||||
height: 56px;
|
||||
background: #ffffff;
|
||||
align-items: center;
|
||||
padding: 12px 24px;
|
||||
border-bottom: 1px solid rgba(31, 35, 41, 0.15);
|
||||
span {
|
||||
font-size: 16px;
|
||||
font-color: #1f2329;
|
||||
font-weight: 500;
|
||||
}
|
||||
.head-right {
|
||||
flex: 1;
|
||||
justify-content: right;
|
||||
.title-search {
|
||||
width: 320px;
|
||||
}
|
||||
.title-type {
|
||||
margin-left: 12px;
|
||||
width: 104px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.template-area {
|
||||
height: calc(100vh - 135px);
|
||||
.template-left {
|
||||
padding: 8px;
|
||||
width: 204px;
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
background: #ffffff;
|
||||
}
|
||||
.template-right {
|
||||
flex: 1;
|
||||
display: inherit;
|
||||
height: 100%;
|
||||
background: rgba(239, 240, 241, 1);
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.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;
|
||||
.template-empty {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
background: rgba(239, 240, 241, 1);
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="less">
|
||||
.custom-line {
|
||||
margin: 4px;
|
||||
background: rgba(31, 35, 41, 0.15);
|
||||
border: 0;
|
||||
height: 1px;
|
||||
}
|
||||
</style>
|
||||
|
136
core/core-frontend/src/views/workbranch/TemplateBranchItem.vue
Normal file
136
core/core-frontend/src/views/workbranch/TemplateBranchItem.vue
Normal file
@ -0,0 +1,136 @@
|
||||
<template>
|
||||
<div class="template">
|
||||
<div class="photo">
|
||||
<div class="img" :style="classBackground"></div>
|
||||
</div>
|
||||
<div class="apply">
|
||||
<span :title="template.title" class="name ellipsis"> {{ template.title }} </span>
|
||||
<el-button class="flex-center" secondary @click="templateInnerPreview">{{
|
||||
t('dataset.preview')
|
||||
}}</el-button>
|
||||
<el-button class="flex-center" type="primary" @click="apply">{{
|
||||
t('commons.apply')
|
||||
}}</el-button>
|
||||
</div>
|
||||
</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
|
||||
}
|
||||
})
|
||||
|
||||
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 apply = () => {
|
||||
emits('templateApply', props.template)
|
||||
}
|
||||
|
||||
const templateInnerPreview = e => {
|
||||
emits('templatePreview', props.template.id)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.template {
|
||||
overflow: hidden;
|
||||
border: 1px solid #d9d9d9;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
width: 181px;
|
||||
height: 141px;
|
||||
margin-left: 16px;
|
||||
position: relative;
|
||||
|
||||
.photo {
|
||||
padding: 4px;
|
||||
padding-bottom: 0;
|
||||
height: 101px;
|
||||
width: 100%;
|
||||
.img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-top-left-radius: 4px;
|
||||
border-top-right-radius: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.apply {
|
||||
padding: 8px 12px;
|
||||
background: #fff;
|
||||
border-top: 1px solid #d9d9d9;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
height: 39px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
border-bottom-left-radius: 4px;
|
||||
border-bottom-right-radius: 4px;
|
||||
justify-content: space-between;
|
||||
|
||||
.ed-button {
|
||||
min-width: 73px;
|
||||
height: 28px;
|
||||
display: none;
|
||||
font-size: 12px;
|
||||
line-height: 20px;
|
||||
padding: 0;
|
||||
margin-top: 8px;
|
||||
& + .ed-button {
|
||||
margin-left: 8px;
|
||||
}
|
||||
}
|
||||
.name {
|
||||
color: #1f2329;
|
||||
font-family: PingFang SC;
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
line-height: 22px;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0px 6px 24px 0px rgba(31, 35, 41, 0.08);
|
||||
.apply {
|
||||
transition: 0.3s;
|
||||
height: 73px;
|
||||
}
|
||||
.ed-button {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,14 +1,18 @@
|
||||
<script lang="ts" setup>
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { ref, shallowRef, computed } from 'vue'
|
||||
import { ref, shallowRef, computed, reactive, watch, nextTick } from 'vue'
|
||||
|
||||
import imgtest from '@/assets/img/dataease-10000Star.jpg'
|
||||
import { usePermissionStoreWithOut } from '@/store/modules/permission'
|
||||
import { useRequestStoreWithOut } from '@/store/modules/request'
|
||||
import { interactiveStoreWithOut } from '@/store/modules/interactive'
|
||||
import ShortcutTable from './ShortcutTable.vue'
|
||||
import { useUserStoreWithOut } from '@/store/modules/user'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { searchMarketRecommend } from '@/api/templateMarket'
|
||||
import TemplateBranchItem from '@/views/workbranch/TemplateBranchItem.vue'
|
||||
import { ElMessage } from 'element-plus-secondary'
|
||||
import { decompression } from '@/api/visualization/dataVisualization'
|
||||
import { useCache } from '@/hooks/web/useCache'
|
||||
const userStore = useUserStoreWithOut()
|
||||
const interactiveStore = interactiveStoreWithOut()
|
||||
const permissionStore = usePermissionStoreWithOut()
|
||||
@ -16,9 +20,8 @@ const requestStore = useRequestStoreWithOut()
|
||||
const { t } = useI18n()
|
||||
const busiDataMap = computed(() => interactiveStore.getData)
|
||||
const busiCountCardList = ref([])
|
||||
|
||||
const showTemplate = ref(false)
|
||||
|
||||
const { wsCache } = useCache()
|
||||
const { push } = useRouter()
|
||||
const router = useRouter()
|
||||
|
||||
const quickCreationList = shallowRef([
|
||||
@ -45,11 +48,89 @@ const handleExpandFold = () => {
|
||||
expandFold.value = expandFold.value === 'expand' ? 'fold' : 'expand'
|
||||
}
|
||||
|
||||
const tabBtnList = ['推荐仪表板', t('auth.screen'), '应用模版']
|
||||
const activeTabBtn = ref('推荐仪表板')
|
||||
const showTemplate = computed(() => {
|
||||
return state.networkStatus && state.hasResult
|
||||
})
|
||||
|
||||
const activeTabChange = value => {
|
||||
activeTabBtn.value = value
|
||||
}
|
||||
|
||||
const tabBtnList = [
|
||||
{
|
||||
name: '推荐仪表板',
|
||||
value: 'PANEL'
|
||||
},
|
||||
{
|
||||
name: t('auth.screen'),
|
||||
value: 'SCREEN'
|
||||
},
|
||||
{
|
||||
name: '应用模版',
|
||||
value: 'APP'
|
||||
}
|
||||
]
|
||||
const activeTabBtn = ref('PANEL')
|
||||
const typeList = quickCreationList.value.map(ele => ele.name)
|
||||
typeList.unshift('all_types')
|
||||
|
||||
const state = reactive({
|
||||
templateType: 'PANEL',
|
||||
baseUrl: null,
|
||||
marketTemplatePreviewShowList: [],
|
||||
hasResult: false,
|
||||
networkStatus: true,
|
||||
loading: false,
|
||||
dvCreateForm: {
|
||||
resourceName: null,
|
||||
name: null,
|
||||
pid: null,
|
||||
nodeType: 'panel',
|
||||
templateUrl: null,
|
||||
newFrom: 'new_market_template',
|
||||
panelType: 'self',
|
||||
panelStyle: {},
|
||||
panelData: '[]'
|
||||
}
|
||||
})
|
||||
|
||||
watch(
|
||||
() => activeTabBtn.value,
|
||||
value => {
|
||||
initTemplateShow()
|
||||
}
|
||||
)
|
||||
|
||||
const initMarketTemplate = async () => {
|
||||
await searchMarketRecommend()
|
||||
.then(rsp => {
|
||||
state.baseUrl = rsp.data.baseUrl
|
||||
state.marketTemplatePreviewShowList = rsp.data.contents
|
||||
state.hasResult = true
|
||||
initTemplateShow()
|
||||
})
|
||||
.catch(() => {
|
||||
state.networkStatus = false
|
||||
})
|
||||
}
|
||||
|
||||
const initTemplateShow = () => {
|
||||
state.hasResult = false
|
||||
state.marketTemplatePreviewShowList.forEach(template => {
|
||||
template.showFlag = templateShowCur(template)
|
||||
if (template.showFlag) {
|
||||
state.hasResult = true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const templateShowCur = templateItem => {
|
||||
let templateTypeMarch = false
|
||||
if (activeTabBtn.value === templateItem.templateType) {
|
||||
templateTypeMarch = true
|
||||
}
|
||||
return templateTypeMarch
|
||||
}
|
||||
const fillCardInfo = () => {
|
||||
for (const key in busiDataMap.value) {
|
||||
if (key !== '3') {
|
||||
@ -99,7 +180,48 @@ const createDatasource = () => {
|
||||
const baseUrl = '#/data/datasource?opt=create'
|
||||
window.open(baseUrl, '_blank')
|
||||
}
|
||||
|
||||
const templatePreview = previewId => {
|
||||
wsCache.set(`template-preview-id`, previewId)
|
||||
toTemplateMarket()
|
||||
}
|
||||
|
||||
const templateApply = template => {
|
||||
state.dvCreateForm.name = template.title
|
||||
state.dvCreateForm.templateUrl = template.metas.theme_repo
|
||||
state.dvCreateForm.resourceName = template.id
|
||||
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 toTemplateMarket = () => {
|
||||
push('/template-market/index')
|
||||
}
|
||||
|
||||
fillCardInfo()
|
||||
initMarketTemplate()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -161,11 +283,11 @@ fillCardInfo()
|
||||
</div>
|
||||
</div>
|
||||
<div class="template-market-dashboard">
|
||||
<div v-if="showTemplate" class="template-market">
|
||||
<div class="template-market">
|
||||
<div class="label">
|
||||
模版市场
|
||||
<div class="expand-all">
|
||||
<button class="all flex-center">查看全部</button>
|
||||
<button class="all flex-center" @click="toTemplateMarket">查看全部</button>
|
||||
<el-divider direction="vertical" />
|
||||
<button @click="handleExpandFold" class="expand flex-center">
|
||||
{{ t(`visualization.${expandFold}`) }}
|
||||
@ -175,37 +297,37 @@ fillCardInfo()
|
||||
<template v-if="expandFold === 'fold'">
|
||||
<div class="tab-btn">
|
||||
<div
|
||||
@click="activeTabBtn = ele"
|
||||
v-for="ele in tabBtnList"
|
||||
:key="ele"
|
||||
:class="activeTabBtn === ele && 'active'"
|
||||
:key="ele.value"
|
||||
:class="activeTabBtn === ele.value && 'active'"
|
||||
@click="activeTabChange(ele.value)"
|
||||
class="main-btn"
|
||||
>
|
||||
{{ ele }}
|
||||
{{ ele.name }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="template-list">
|
||||
<div class="template">
|
||||
<div class="photo">
|
||||
<img :src="imgtest" alt="" />
|
||||
</div>
|
||||
<div class="apply">
|
||||
<span title="电子银行业务分析" class="name ellipsis"> 电子银行业务分析 </span>
|
||||
<el-button class="flex-center" secondary>{{ t('dataset.preview') }}</el-button>
|
||||
<el-button class="flex-center" type="primary">{{ t('commons.apply') }}</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="template">
|
||||
<div class="photo">
|
||||
<img :src="imgtest" alt="" />
|
||||
</div>
|
||||
<div class="apply">
|
||||
<span title="电子银行业务分析" class="name ellipsis"> 电子银行业务分析 </span>
|
||||
<el-button class="flex-center" secondary>{{ t('dataset.preview') }}</el-button>
|
||||
<el-button class="flex-center" type="primary">{{ t('commons.apply') }}</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="template-list" v-show="state.networkStatus && state.hasResult">
|
||||
<template-branch-item
|
||||
v-for="(template, index) in state.marketTemplatePreviewShowList"
|
||||
v-show="template['showFlag']"
|
||||
:key="index"
|
||||
:template="template"
|
||||
:base-url="state.baseUrl"
|
||||
@templateApply="templateApply"
|
||||
@templatePreview="templatePreview"
|
||||
>
|
||||
</template-branch-item>
|
||||
</div>
|
||||
<el-row v-show="state.networkStatus && !state.hasResult" class="template-empty">
|
||||
<div style="text-align: center">
|
||||
<Icon name="no_result" class="no-result"></Icon>
|
||||
<br />
|
||||
<span class="no-result-tips">没有找到相关模版</span>
|
||||
</div>
|
||||
</el-row>
|
||||
<el-row v-show="!state.networkStatus" class="template-empty">
|
||||
{{ t('visualization.market_network_tips') }}
|
||||
</el-row>
|
||||
</template>
|
||||
</div>
|
||||
<shortcut-table :expand="expandFold === 'expand'" />
|
||||
@ -473,78 +595,25 @@ fillCardInfo()
|
||||
.template-list {
|
||||
display: flex;
|
||||
margin-left: -16px;
|
||||
.template {
|
||||
border: 1px solid #d9d9d9;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
width: 181px;
|
||||
height: 141px;
|
||||
margin-left: 16px;
|
||||
position: relative;
|
||||
|
||||
.photo {
|
||||
padding: 4px;
|
||||
padding-bottom: 0;
|
||||
height: 101px;
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-top-left-radius: 4px;
|
||||
border-top-right-radius: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.apply {
|
||||
padding: 8px 12px;
|
||||
background: #fff;
|
||||
border-top: 1px solid #d9d9d9;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
height: 39px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
border-bottom-left-radius: 4px;
|
||||
border-bottom-right-radius: 4px;
|
||||
justify-content: space-between;
|
||||
|
||||
.ed-button {
|
||||
min-width: 73px;
|
||||
height: 28px;
|
||||
display: none;
|
||||
font-size: 12px;
|
||||
line-height: 20px;
|
||||
padding: 0;
|
||||
margin-top: 8px;
|
||||
& + .ed-button {
|
||||
margin-left: 8px;
|
||||
}
|
||||
}
|
||||
.name {
|
||||
color: #1f2329;
|
||||
font-family: PingFang SC;
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
line-height: 22px;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0px 6px 24px 0px rgba(31, 35, 41, 0.08);
|
||||
.apply {
|
||||
height: 73px;
|
||||
}
|
||||
.ed-button {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.template-empty {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: rgba(239, 240, 241, 1);
|
||||
color: rgba(100, 106, 115, 1);
|
||||
min-height: 60px;
|
||||
}
|
||||
.no-result {
|
||||
width: 74px;
|
||||
height: 74px;
|
||||
}
|
||||
.no-result-tips {
|
||||
font-size: 14px;
|
||||
color: rgba(100, 106, 115, 1);
|
||||
}
|
||||
</style>
|
||||
|
@ -2,6 +2,8 @@ package io.dataease.api.template;
|
||||
|
||||
import io.dataease.api.template.request.TemplateMarketSearchRequest;
|
||||
import io.dataease.api.template.response.MarketBaseResponse;
|
||||
import io.dataease.api.template.response.MarketPreviewBaseResponse;
|
||||
import io.dataease.api.template.vo.MarketMetaDataVO;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
@ -16,8 +18,16 @@ public interface TemplateMarketApi {
|
||||
|
||||
@GetMapping("/search")
|
||||
MarketBaseResponse searchTemplate();
|
||||
@GetMapping("/searchRecommend")
|
||||
MarketBaseResponse searchTemplateRecommend();
|
||||
|
||||
@GetMapping("/searchPreview")
|
||||
MarketPreviewBaseResponse searchTemplatePreview();
|
||||
|
||||
@GetMapping("/categories")
|
||||
List<String> categories();
|
||||
|
||||
@GetMapping("/categoriesObject")
|
||||
List<MarketMetaDataVO> categoriesObject() ;
|
||||
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import java.util.List;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class TemplateMarketDTO {
|
||||
public class TemplateMarketDTO implements Comparable<TemplateMarketDTO> {
|
||||
private String id;
|
||||
private String title;
|
||||
private String status;
|
||||
@ -20,15 +20,35 @@ public class TemplateMarketDTO {
|
||||
private String editorType;
|
||||
private String summary;
|
||||
private String thumbnail;
|
||||
|
||||
private Boolean showFlag = true;
|
||||
|
||||
private String suggest = "N";
|
||||
|
||||
private Long recentUseTime = 0L;
|
||||
|
||||
private String templateType;
|
||||
private List<MarketCategoryVO> categories;
|
||||
private MarketMetasVO metas;
|
||||
|
||||
public TemplateMarketDTO(String id, String title,String themeRepo,String templateUrl,String categoryName) {
|
||||
|
||||
public TemplateMarketDTO(String id, String title, String themeRepo, String templateUrl, String categoryName, String templateType, Long recentUseTime,String suggest) {
|
||||
this.id = id;
|
||||
this.title = title;
|
||||
this.categories = Arrays.asList(new MarketCategoryVO(categoryName),new MarketCategoryVO("全部"));
|
||||
this.categories = Arrays.asList(new MarketCategoryVO(categoryName), new MarketCategoryVO("全部"));
|
||||
this.metas = new MarketMetasVO(templateUrl);
|
||||
this.thumbnail = themeRepo;
|
||||
this.templateType = templateType;
|
||||
if (recentUseTime != null) {
|
||||
this.recentUseTime = recentUseTime;
|
||||
}
|
||||
if("Y".equalsIgnoreCase(suggest)){
|
||||
this.suggest="Y";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(TemplateMarketDTO other) {
|
||||
return Long.compare(other.recentUseTime, this.recentUseTime);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,24 @@
|
||||
package io.dataease.api.template.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author : WangJiaHao
|
||||
* @date : 2023/11/27
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class TemplateMarketPreviewInfoDTO {
|
||||
|
||||
private String categoryType;
|
||||
|
||||
List<TemplateMarketDTO> contents;
|
||||
|
||||
public TemplateMarketPreviewInfoDTO(String categoryType, List<TemplateMarketDTO> contents) {
|
||||
this.categoryType = categoryType;
|
||||
this.contents = contents;
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package io.dataease.api.template.response;
|
||||
|
||||
import io.dataease.api.template.dto.TemplateMarketDTO;
|
||||
import io.dataease.api.template.dto.TemplateMarketPreviewInfoDTO;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author : WangJiaHao
|
||||
* @date : 2023/11/6 17:43
|
||||
*/
|
||||
@Data
|
||||
public class MarketPreviewBaseResponse {
|
||||
private String baseUrl;
|
||||
|
||||
private List<String> categories;
|
||||
|
||||
private List<TemplateMarketPreviewInfoDTO> contents;
|
||||
|
||||
public MarketPreviewBaseResponse() {
|
||||
}
|
||||
|
||||
public MarketPreviewBaseResponse(String baseUrl, List<String> categories, List<TemplateMarketPreviewInfoDTO> contents) {
|
||||
this.baseUrl = baseUrl;
|
||||
this.categories = categories;
|
||||
this.contents = contents;
|
||||
}
|
||||
}
|
@ -24,6 +24,9 @@ public class MarketApplicationSpecVO {
|
||||
|
||||
private String readmeName;
|
||||
|
||||
// 是否推荐
|
||||
private String suggest;
|
||||
|
||||
private List<MarketApplicationSpecScreenshotBaseVO> screenshots;
|
||||
|
||||
private List<MarketApplicationSpecLinkVO> links;
|
||||
|
@ -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 MarketMetaDataVO {
|
||||
private String slug;
|
||||
private String value;
|
||||
private String label;
|
||||
|
||||
public MarketMetaDataVO(String value, String label) {
|
||||
this.label = label;
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,8 @@ public class DataVisualizationBaseRequest extends DataVisualizationVO {
|
||||
|
||||
private String opt;
|
||||
|
||||
private String resourceName;
|
||||
|
||||
private Boolean moveFromUpdate = false;
|
||||
|
||||
private String optType;
|
||||
|
Loading…
Reference in New Issue
Block a user