forked from github/dataease
Merge pull request #6770 from dataease/pr@dev@refactor_template-market
refactor: 对接V2模版市场正式环境优化
This commit is contained in:
commit
341dd0763b
@ -1,24 +1,22 @@
|
||||
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.MarketCategoryBaseResponse;
|
||||
import io.dataease.api.template.response.MarketTemplateBaseResponse;
|
||||
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;
|
||||
import io.dataease.utils.HttpClientConfig;
|
||||
import io.dataease.utils.HttpClientUtil;
|
||||
import io.dataease.utils.JsonUtil;
|
||||
import io.swagger.v3.core.util.Json;
|
||||
import jakarta.annotation.Resource;
|
||||
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;
|
||||
@ -31,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;
|
||||
|
||||
@ -44,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;
|
||||
}
|
||||
@ -62,7 +64,29 @@ public class TemplateMarketManage {
|
||||
|
||||
public MarketBaseResponse searchTemplate() {
|
||||
try {
|
||||
Map<String,String> templateParams = sysParameterManage.groupVal("template.");
|
||||
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;
|
||||
}
|
||||
|
||||
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());
|
||||
@ -73,8 +97,8 @@ public class TemplateMarketManage {
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<String> getCategories() {
|
||||
Map<String,String> templateParams = sysParameterManage.groupVal("template.");
|
||||
public List<String> getCategoriesV1() {
|
||||
Map<String, String> templateParams = sysParameterManage.groupVal("template.");
|
||||
String resultStr = marketGet(templateParams.get("template.url") + CATEGORIES_API, templateParams.get("template.accessKey"));
|
||||
MarketCategoryBaseResponse categoryBaseResponse = JsonUtil.parseObject(resultStr, MarketCategoryBaseResponse.class);
|
||||
List<TemplateCategoryVO> categories = categoryBaseResponse.getData();
|
||||
@ -85,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;
|
||||
}
|
||||
}
|
||||
|
@ -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:
|
||||
|
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 |
@ -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>
|
||||
|
@ -1,96 +1,98 @@
|
||||
<template>
|
||||
<el-row style="display: inherit">
|
||||
<el-col :class="state.asideActive ? 'aside-active' : 'aside-inActive'">
|
||||
<svg-icon
|
||||
v-show="!state.asideActive"
|
||||
icon-class="button_right"
|
||||
class="open-button"
|
||||
@click="asideActiveChange(true)"
|
||||
/>
|
||||
<el-row v-show="state.asideActive" style="padding: 12px 12px 0">
|
||||
<el-row>
|
||||
<span class="icon iconfont icon-close icon20 insert" @click="closePreview()" />
|
||||
<span class="main-title">{{ t('visualization.template_preview') }}</span>
|
||||
<span
|
||||
style="float: right"
|
||||
class="icon iconfont icon-icon_up-left_outlined insert icon20"
|
||||
@click="asideActiveChange(false)"
|
||||
/>
|
||||
<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 class="margin-top16 search-area">
|
||||
<el-input
|
||||
v-model="state.searchText"
|
||||
size="small"
|
||||
prefix-icon="el-icon-search"
|
||||
class="title-name-search"
|
||||
:placeholder="t('visualization.enter_template_name_tips')"
|
||||
clearable="true"
|
||||
/>
|
||||
<span
|
||||
class="icon iconfont icon-icon-filter insert-filter filter-icon-span"
|
||||
:class="state.extFilterActive ? 'filter-icon-active' : ''"
|
||||
@click="extFilterActiveChange()"
|
||||
/>
|
||||
</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' : ''"
|
||||
<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' : ''"
|
||||
>
|
||||
<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">
|
||||
<svg-icon icon-class="no_result" style="margin-bottom: 16px; font-size: 75px" />
|
||||
<br />
|
||||
<span>{{ t('commons.no_result') }}</span>
|
||||
<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>
|
||||
</el-col>
|
||||
<el-col class="main-area" :class="state.asideActive ? 'main-area-active' : ''">
|
||||
<el-row>
|
||||
<span v-if="state.curTemplate" class="template-title">{{ state.curTemplate.title }}</span>
|
||||
<el-button
|
||||
style="float: right"
|
||||
type="primary"
|
||||
size="small"
|
||||
@click="templateApply(state.curTemplate)"
|
||||
>{{ t('visualization.apply_this_template') }}</el-button
|
||||
>
|
||||
</el-row>
|
||||
<el-row class="img-main">
|
||||
<img height="100%" :src="state.templatePreviewUrl" alt="" />
|
||||
</el-row>
|
||||
</el-col>
|
||||
<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 TemplateMarketPreviewItem from '@/views/template-market/component/TemplateMarketPreviewItem.vue'
|
||||
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({
|
||||
@ -129,6 +131,13 @@ watch(
|
||||
|
||||
watch(
|
||||
() => state.searchText,
|
||||
value => {
|
||||
initTemplateShow()
|
||||
}
|
||||
)
|
||||
|
||||
watch(
|
||||
() => props.previewId,
|
||||
value => {
|
||||
state.currentMarketTemplateShowList.forEach(template => {
|
||||
if (value === template.id) {
|
||||
@ -314,7 +323,7 @@ onMounted(() => {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
justify-content: center;
|
||||
font-size: 14px;
|
||||
flex-flow: row nowrap;
|
||||
color: #646a73;
|
||||
@ -356,6 +365,7 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
.main-title {
|
||||
width: 135px;
|
||||
margin-left: 8px;
|
||||
font-weight: 500;
|
||||
font-size: 16px;
|
||||
@ -434,6 +444,7 @@ onMounted(() => {
|
||||
margin-top: 16px;
|
||||
}
|
||||
.img-main {
|
||||
display: inherit;
|
||||
border-radius: 4px;
|
||||
background: #0f1114;
|
||||
overflow-x: auto;
|
||||
|
@ -1,13 +1,13 @@
|
||||
<template>
|
||||
<div class="testcase-template">
|
||||
<div class="template-img" :style="classBackground" @click.stop="templatePreview" />
|
||||
<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="templatePreview">{{
|
||||
<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">{{
|
||||
@ -61,7 +61,7 @@ const apply = () => {
|
||||
emits('templateApply', props.template)
|
||||
}
|
||||
|
||||
const templatePreview = () => {
|
||||
const templateInnerPreview = e => {
|
||||
emits('templatePreview', props.template.id)
|
||||
}
|
||||
</script>
|
||||
|
@ -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>
|
||||
|
@ -1,414 +0,0 @@
|
||||
<template>
|
||||
<el-row class="outer-body">
|
||||
<!--预览模式-->
|
||||
<market-preview
|
||||
v-show="state.previewModel"
|
||||
:preview-id="state.templatePreviewId"
|
||||
@closePreview="state.previewModel = false"
|
||||
@templateApply="templateApply"
|
||||
/>
|
||||
<!--列表模式-->
|
||||
<el-row v-show="!state.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 style="display: inherit">
|
||||
<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"
|
||||
:style="{ width: state.templateSpan }"
|
||||
>
|
||||
<template-market-item
|
||||
: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">
|
||||
<svg-icon icon-class="no_result" style="margin-bottom: 16px; font-size: 75px" />
|
||||
<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-dialog
|
||||
:title="t('visualization.apply_template')"
|
||||
v-model="state.folderSelectShow"
|
||||
width="600px"
|
||||
class="market-dialog-css"
|
||||
:append-to-body="true"
|
||||
:destroy-on-close="true"
|
||||
>
|
||||
<el-form ref="panelForm" :model="state.panelForm" :rules="rule" label-width="80px">
|
||||
<el-form-item :label="t('visualization.name')" prop="name">
|
||||
<el-input
|
||||
v-model="state.panelForm.name"
|
||||
:clearable="true"
|
||||
:placeholder="t('visualization.enter_name_tips')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('commons.folder')" prop="pid">
|
||||
<treeselect
|
||||
v-model="state.panelForm.pid"
|
||||
:clearable="false"
|
||||
:options="state.panelGroupList"
|
||||
:normalizer="normalizer"
|
||||
:placeholder="t('chart.select_group')"
|
||||
:no-children-text="t('commons.treeselect.no_children_text')"
|
||||
:no-options-text="t('commons.treeselect.no_options_text')"
|
||||
:no-results-text="t('commons.treeselect.no_results_text')"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer dialog-footer-self">
|
||||
<el-button size="mini" @click="state.folderSelectShow = false"
|
||||
>{{ t('commons.cancel') }}
|
||||
</el-button>
|
||||
<el-button
|
||||
size="mini"
|
||||
type="primary"
|
||||
:disabled="!state.panelForm.name || !state.panelForm.pid"
|
||||
@click="apply"
|
||||
>{{ t('commons.confirm') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { getCategories, searchMarket } from '@/api/templateMarket'
|
||||
import elementResizeDetectorMaker from 'element-resize-detector'
|
||||
import { nextTick, reactive, watch, onMounted } 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'
|
||||
const { t } = useI18n()
|
||||
|
||||
const emits = defineEmits(['closeDialog'])
|
||||
|
||||
const state = reactive({
|
||||
hasResult: true,
|
||||
templateMiniWidth: 330,
|
||||
templateCurWidth: 310,
|
||||
templateSpan: '25%',
|
||||
previewModel: false,
|
||||
previewVisible: false,
|
||||
templatePreviewId: '',
|
||||
marketTabs: null,
|
||||
marketActiveTab: null,
|
||||
searchText: null,
|
||||
panelForm: {
|
||||
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 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.panelForm.name = template.title
|
||||
state.panelForm.templateUrl = state.baseUrl + template.metas.theme_repo
|
||||
state.folderSelectShow = true
|
||||
}
|
||||
|
||||
const apply = () => {
|
||||
if (state.panelForm.name.length > 50) {
|
||||
ElMessage.warning(t('commons.char_can_not_more_50'))
|
||||
return false
|
||||
}
|
||||
|
||||
if (!state.panelForm.templateUrl) {
|
||||
ElMessage.warning('未获取模板下载链接请联系模板市场官方')
|
||||
return false
|
||||
}
|
||||
// panelSave(state.panelForm)
|
||||
// .then(response => {
|
||||
// state.$message({
|
||||
// message: state.t('commons.save_success'),
|
||||
// type: 'success',
|
||||
// showClose: true
|
||||
// })
|
||||
// state.folderSelectShow = false
|
||||
// state.$router.push({ name: 'panel', params: response.data })
|
||||
// })
|
||||
// .catch(() => {
|
||||
// state.loading = false
|
||||
// })
|
||||
}
|
||||
const closeDialog = () => {
|
||||
emits('closeDialog')
|
||||
}
|
||||
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
|
||||
state.previewModel = 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>
|
||||
.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 {
|
||||
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: space-between;
|
||||
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>
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -23,4 +23,6 @@ public class MarketBaseResponse {
|
||||
this.contents = contents;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -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,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;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user