forked from github/dataease
Merge branch 'dev-v2' into pr@dev-v2_dzz
This commit is contained in:
commit
30479ddfc1
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -21,12 +21,16 @@ public class DeMvcConfig implements WebMvcConfigurer {
|
||||
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
||||
String workDir = FILE_PROTOCOL + ensureSuffix(WORK_DIR, FILE_SEPARATOR);
|
||||
String uploadUrlPattern = ensureBoth(URL_SEPARATOR + UPLOAD_URL_PREFIX, AuthConstant.DE_API_PREFIX, URL_SEPARATOR) + "**";
|
||||
registry.addResourceHandler(uploadUrlPattern)
|
||||
.addResourceLocations(workDir);
|
||||
registry.addResourceHandler(uploadUrlPattern).addResourceLocations(workDir);
|
||||
|
||||
// map
|
||||
String mapDir = FILE_PROTOCOL + ensureSuffix(MAP_DIR, FILE_SEPARATOR);
|
||||
String mapUrlPattern = ensureBoth(MAP_URL, AuthConstant.DE_API_PREFIX, URL_SEPARATOR) + "**";
|
||||
registry.addResourceHandler(mapUrlPattern)
|
||||
.addResourceLocations(mapDir);
|
||||
registry.addResourceHandler(mapUrlPattern).addResourceLocations(mapDir);
|
||||
|
||||
String geoDir = FILE_PROTOCOL + ensureSuffix(CUSTOM_MAP_DIR, FILE_SEPARATOR);
|
||||
String geoUrlPattern = ensureBoth(GEO_URL, AuthConstant.DE_API_PREFIX, URL_SEPARATOR) + "**";
|
||||
registry.addResourceHandler(geoUrlPattern).addResourceLocations(geoDir);
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,6 @@ import io.dataease.datasource.request.DatasourceRequest;
|
||||
import io.dataease.datasource.server.EngineServer;
|
||||
import io.dataease.datasource.type.*;
|
||||
import io.dataease.engine.constant.SQLConstants;
|
||||
import io.dataease.engine.func.scalar.ScalarFunctions;
|
||||
import io.dataease.exception.DEException;
|
||||
import io.dataease.i18n.Translator;
|
||||
import io.dataease.utils.BeanUtils;
|
||||
@ -26,6 +25,7 @@ import io.dataease.utils.LogUtil;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.apache.calcite.adapter.jdbc.JdbcSchema;
|
||||
import org.apache.calcite.func.scalar.ScalarFunctions;
|
||||
import org.apache.calcite.jdbc.CalciteConnection;
|
||||
import org.apache.calcite.schema.Schema;
|
||||
import org.apache.calcite.schema.SchemaPlus;
|
||||
|
@ -1,194 +0,0 @@
|
||||
package io.dataease.engine.func.scalar;
|
||||
|
||||
import io.dataease.engine.utils.Utils;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
public class ScalarFunctions {
|
||||
public static String format = "yyyy-MM-dd HH:mm:ss";
|
||||
public static String minuteFormat = "yyyy-MM-dd HH:mm";
|
||||
public static String hourFormat = "yyyy-MM-dd HH";
|
||||
public static String dateOnly = "yyyy-MM-dd";
|
||||
public static String monthOnly = "yyyy-MM";
|
||||
public static String yearOnly = "yyyy";
|
||||
public static String timeOnly = "HH:mm:ss";
|
||||
|
||||
public static String date_format(String date, String format) {
|
||||
try {
|
||||
if (StringUtils.isEmpty(date)) {
|
||||
return null;
|
||||
}
|
||||
format = get_date_format(date);
|
||||
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);
|
||||
Date parse = simpleDateFormat.parse(date);
|
||||
return simpleDateFormat.format(parse);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static String de_date_format(String date, String format) {
|
||||
try {
|
||||
if (StringUtils.isEmpty(date)) {
|
||||
return null;
|
||||
}
|
||||
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);
|
||||
Date parse = simpleDateFormat.parse(date);
|
||||
return simpleDateFormat.format(parse);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static String str_to_date(String date, String format) {
|
||||
try {
|
||||
if (StringUtils.isEmpty(date)) {
|
||||
return null;
|
||||
}
|
||||
format = get_date_format(date);
|
||||
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);
|
||||
Date parse = simpleDateFormat.parse(date);
|
||||
return simpleDateFormat.format(parse);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static String de_str_to_date(String date, String format) {
|
||||
try {
|
||||
if (StringUtils.isEmpty(date)) {
|
||||
return null;
|
||||
}
|
||||
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);
|
||||
Date parse = simpleDateFormat.parse(date);
|
||||
return simpleDateFormat.format(parse);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static String cast_date_format(String date, String sourceFormat, String targetFormat) {
|
||||
try {
|
||||
if (StringUtils.isEmpty(date)) {
|
||||
return null;
|
||||
}
|
||||
sourceFormat = get_date_format(date);
|
||||
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(sourceFormat);
|
||||
Date parse = simpleDateFormat.parse(date);
|
||||
|
||||
SimpleDateFormat s = new SimpleDateFormat(targetFormat);
|
||||
return s.format(parse);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static String de_cast_date_format(String date, String sourceFormat, String targetFormat) {
|
||||
try {
|
||||
if (StringUtils.isEmpty(date)) {
|
||||
return null;
|
||||
}
|
||||
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(sourceFormat);
|
||||
Date parse = simpleDateFormat.parse(date);
|
||||
|
||||
SimpleDateFormat s = new SimpleDateFormat(targetFormat);
|
||||
return s.format(parse);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static Long unix_timestamp(String date) {
|
||||
try {
|
||||
if (StringUtils.isEmpty(date)) {
|
||||
return null;
|
||||
}
|
||||
return Utils.allDateFormat2Long(date);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static String get_date_format(String date) {
|
||||
// check date split '-' or '/'
|
||||
String format1 = format;
|
||||
String minuteFormat1 = minuteFormat;
|
||||
String hourFormat1 = hourFormat;
|
||||
String timeOnly1 = timeOnly;
|
||||
String dateOnly1 = dateOnly;
|
||||
String monthOnly1 = monthOnly;
|
||||
String yearOnly1 = yearOnly;
|
||||
if (date != null && date.contains("/")) {
|
||||
format1 = format1.replaceAll("-", "/");
|
||||
minuteFormat1 = minuteFormat1.replaceAll("-", "/");
|
||||
hourFormat1 = hourFormat1.replaceAll("-", "/");
|
||||
timeOnly1 = timeOnly1.replaceAll("-", "/");
|
||||
dateOnly1 = dateOnly1.replaceAll("-", "/");
|
||||
monthOnly1 = monthOnly1.replaceAll("-", "/");
|
||||
yearOnly1 = yearOnly1.replaceAll("-", "/");
|
||||
}
|
||||
try {
|
||||
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format1);
|
||||
simpleDateFormat.parse(date);
|
||||
return format1;
|
||||
} catch (Exception e) {
|
||||
}
|
||||
try {
|
||||
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(minuteFormat1);
|
||||
simpleDateFormat.parse(date);
|
||||
return minuteFormat1;
|
||||
} catch (Exception e) {
|
||||
}
|
||||
try {
|
||||
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(hourFormat1);
|
||||
simpleDateFormat.parse(date);
|
||||
return hourFormat1;
|
||||
} catch (Exception e) {
|
||||
}
|
||||
try {
|
||||
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(timeOnly1);
|
||||
simpleDateFormat.parse(date);
|
||||
return timeOnly1;
|
||||
} catch (Exception e) {
|
||||
}
|
||||
try {
|
||||
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(dateOnly1);
|
||||
simpleDateFormat.parse(date);
|
||||
return dateOnly1;
|
||||
} catch (Exception e) {
|
||||
}
|
||||
try {
|
||||
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(monthOnly1);
|
||||
simpleDateFormat.parse(date);
|
||||
return monthOnly1;
|
||||
} catch (Exception e) {
|
||||
}
|
||||
try {
|
||||
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(yearOnly1);
|
||||
simpleDateFormat.parse(date);
|
||||
return yearOnly1;
|
||||
} catch (Exception e) {
|
||||
}
|
||||
return format1;
|
||||
}
|
||||
|
||||
public static String from_unixtime(Long timestamp, String format) {
|
||||
try {
|
||||
if (ObjectUtils.isEmpty(timestamp)) {
|
||||
return null;
|
||||
}
|
||||
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);
|
||||
Date date = new Date(timestamp);
|
||||
return simpleDateFormat.format(date);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static String concat(String str1, String str2) {
|
||||
return str1 + str2;
|
||||
}
|
||||
}
|
@ -6,8 +6,8 @@ import io.dataease.api.dataset.union.model.SQLMeta;
|
||||
import io.dataease.api.dataset.union.model.SQLObj;
|
||||
import io.dataease.dto.dataset.DatasetTableFieldDTO;
|
||||
import io.dataease.engine.constant.SQLConstants;
|
||||
import io.dataease.engine.func.scalar.ScalarFunctions;
|
||||
import io.dataease.engine.utils.Utils;
|
||||
import org.apache.calcite.func.scalar.ScalarFunctions;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
|
@ -5,8 +5,8 @@ import io.dataease.api.dataset.union.model.SQLMeta;
|
||||
import io.dataease.api.dataset.union.model.SQLObj;
|
||||
import io.dataease.dto.dataset.DatasetTableFieldDTO;
|
||||
import io.dataease.engine.constant.SQLConstants;
|
||||
import io.dataease.engine.func.scalar.ScalarFunctions;
|
||||
import io.dataease.engine.utils.Utils;
|
||||
import org.apache.calcite.func.scalar.ScalarFunctions;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
@ -55,7 +55,7 @@ public class ExtWhere2Str {
|
||||
if (field.getDeType() == 1) {
|
||||
String date_format;
|
||||
if (StringUtils.containsIgnoreCase(request.getOperator(), "between")) {
|
||||
date_format = ScalarFunctions.format;
|
||||
date_format = "yyyy-MM-dd HH:mm:ss";
|
||||
} else {
|
||||
date_format = ScalarFunctions.get_date_format(value.get(0));
|
||||
}
|
||||
|
@ -8,8 +8,8 @@ import io.dataease.api.permissions.dataset.dto.DatasetRowPermissionsTreeObj;
|
||||
import io.dataease.dto.dataset.DatasetTableFieldDTO;
|
||||
import io.dataease.engine.constant.ExtFieldConstant;
|
||||
import io.dataease.engine.constant.SQLConstants;
|
||||
import io.dataease.engine.func.scalar.ScalarFunctions;
|
||||
import io.dataease.engine.utils.Utils;
|
||||
import org.apache.calcite.func.scalar.ScalarFunctions;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
@ -0,0 +1,13 @@
|
||||
package io.dataease.map.bo;
|
||||
|
||||
import io.dataease.map.dao.auto.entity.Area;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class AreaBO extends Area implements Serializable {
|
||||
private boolean custom = false;
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package io.dataease.map.dao.ext.entity;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
public class CoreAreaCustom implements Serializable {
|
||||
|
||||
private String id;
|
||||
|
||||
private String pid;
|
||||
|
||||
private String name;
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package io.dataease.map.dao.ext.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import io.dataease.map.dao.ext.entity.CoreAreaCustom;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface CoreAreaCustomMapper extends BaseMapper<CoreAreaCustom> {
|
||||
}
|
@ -1,17 +1,34 @@
|
||||
package io.dataease.map.manage;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import io.dataease.api.map.dto.GeometryNodeCreator;
|
||||
import io.dataease.api.map.vo.AreaNode;
|
||||
import io.dataease.constant.StaticResourceConstants;
|
||||
import io.dataease.exception.DEException;
|
||||
import io.dataease.map.bo.AreaBO;
|
||||
import io.dataease.map.dao.auto.entity.Area;
|
||||
import io.dataease.map.dao.auto.mapper.AreaMapper;
|
||||
import io.dataease.map.dao.ext.entity.CoreAreaCustom;
|
||||
import io.dataease.map.dao.ext.mapper.CoreAreaCustomMapper;
|
||||
import io.dataease.utils.BeanUtils;
|
||||
import io.dataease.utils.CommonBeanFactory;
|
||||
import io.dataease.utils.LogUtil;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static io.dataease.constant.CacheConstant.CommonCacheConstant.WORLD_MAP_CACHE;
|
||||
|
||||
@ -19,6 +36,8 @@ import static io.dataease.constant.CacheConstant.CommonCacheConstant.WORLD_MAP_C
|
||||
public class MapManage {
|
||||
private final static AreaNode WORLD;
|
||||
|
||||
private static final String GEO_PREFIX = "geo_";
|
||||
|
||||
static {
|
||||
WORLD = AreaNode.builder()
|
||||
.id("000")
|
||||
@ -30,13 +49,34 @@ public class MapManage {
|
||||
@Resource
|
||||
private AreaMapper areaMapper;
|
||||
|
||||
@Resource
|
||||
private CoreAreaCustomMapper coreAreaCustomMapper;
|
||||
|
||||
public List<Area> defaultArea() {
|
||||
return areaMapper.selectList(null);
|
||||
}
|
||||
|
||||
private MapManage proxy() {
|
||||
return CommonBeanFactory.getBean(MapManage.class);
|
||||
}
|
||||
|
||||
@Cacheable(value = WORLD_MAP_CACHE, key = "'world_map'")
|
||||
public AreaNode getWorldTree() {
|
||||
List<Area> areas = areaMapper.selectList(null);
|
||||
List<Area> areas = proxy().defaultArea();
|
||||
List<AreaBO> areaBOS = areas.stream().map(item -> BeanUtils.copyBean(new AreaBO(), item)).collect(Collectors.toList());
|
||||
List<CoreAreaCustom> coreAreaCustoms = coreAreaCustomMapper.selectList(null);
|
||||
if (CollectionUtils.isNotEmpty(coreAreaCustoms)) {
|
||||
List<AreaBO> customBoList = coreAreaCustoms.stream().map(item -> {
|
||||
AreaBO areaBO = BeanUtils.copyBean(new AreaBO(), item);
|
||||
areaBO.setCustom(true);
|
||||
return areaBO;
|
||||
}).toList();
|
||||
areaBOS.addAll(customBoList);
|
||||
}
|
||||
WORLD.setChildren(new ArrayList<>());
|
||||
var areaNodeMap = new HashMap<String, AreaNode>();
|
||||
areaNodeMap.put(WORLD.getId(), WORLD);
|
||||
areas.forEach(area -> {
|
||||
areaBOS.forEach(area -> {
|
||||
var node = areaNodeMap.get(area.getId());
|
||||
if (node == null) {
|
||||
node = AreaNode.builder().build();
|
||||
@ -64,5 +104,80 @@ public class MapManage {
|
||||
return WORLD;
|
||||
}
|
||||
|
||||
@CacheEvict(cacheNames = WORLD_MAP_CACHE, key = "'world_map'")
|
||||
@Transactional
|
||||
public void saveMapGeo(GeometryNodeCreator request, MultipartFile file) {
|
||||
List<Area> areas = proxy().defaultArea();
|
||||
String code = getBusiGeoCode(request.getCode());
|
||||
|
||||
AtomicReference<String> atomicReference = new AtomicReference<>();
|
||||
if (areas.stream().anyMatch(area -> {
|
||||
boolean exist = area.getId().equals(code);
|
||||
if (exist) {
|
||||
atomicReference.set(area.getName());
|
||||
}
|
||||
return exist;
|
||||
})) {
|
||||
DEException.throwException(String.format("Area code [%s] is already exists for [%s]", code, atomicReference.get()));
|
||||
}
|
||||
|
||||
CoreAreaCustom originData = null;
|
||||
if (ObjectUtils.isNotEmpty(originData = coreAreaCustomMapper.selectById(getDaoGeoCode(code)))) {
|
||||
DEException.throwException(String.format("Area code [%s] is already exists for [%s]", code, originData.getName()));
|
||||
}
|
||||
|
||||
CoreAreaCustom coreAreaCustom = new CoreAreaCustom();
|
||||
coreAreaCustom.setId(getDaoGeoCode(code));
|
||||
coreAreaCustom.setPid(request.getPid());
|
||||
coreAreaCustom.setName(request.getName());
|
||||
coreAreaCustomMapper.insert(coreAreaCustom);
|
||||
|
||||
File geoFile = buildGeoFile(code);
|
||||
try {
|
||||
file.transferTo(geoFile);
|
||||
} catch (IOException e) {
|
||||
LogUtil.error(e.getMessage());
|
||||
DEException.throwException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@CacheEvict(cacheNames = WORLD_MAP_CACHE, key = "'world_map'")
|
||||
@Transactional
|
||||
public void deleteGeo(String code) {
|
||||
if (!StringUtils.startsWith(code, GEO_PREFIX)) {
|
||||
DEException.throwException("内置Geometry,禁止删除");
|
||||
}
|
||||
coreAreaCustomMapper.deleteById(code);
|
||||
File file = buildGeoFile(code);
|
||||
if (file.exists()) {
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
|
||||
private String getDaoGeoCode(String code) {
|
||||
return StringUtils.startsWith(code, GEO_PREFIX) ? code : (GEO_PREFIX + code);
|
||||
}
|
||||
|
||||
private String getBusiGeoCode(String code) {
|
||||
return StringUtils.startsWith(code, GEO_PREFIX) ? code.substring(GEO_PREFIX.length()) : code;
|
||||
}
|
||||
|
||||
private File buildGeoFile(String code) {
|
||||
String id = getBusiGeoCode(code);
|
||||
String customMapDir = StaticResourceConstants.CUSTOM_MAP_DIR;
|
||||
String countryCode = countryCode(id);
|
||||
String fileDirPath = customMapDir + "/" + countryCode + "/";
|
||||
File dir = new File(fileDirPath);
|
||||
if (!dir.exists()) {
|
||||
dir.mkdirs();
|
||||
}
|
||||
String filePath = fileDirPath + id + ".json";
|
||||
return new File(filePath);
|
||||
}
|
||||
|
||||
private String countryCode(String code) {
|
||||
return code.substring(0, 3);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,26 @@
|
||||
package io.dataease.map.server;
|
||||
|
||||
import io.dataease.api.map.GeoApi;
|
||||
import io.dataease.api.map.dto.GeometryNodeCreator;
|
||||
import io.dataease.map.manage.MapManage;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/geometry")
|
||||
public class GeoServer implements GeoApi {
|
||||
|
||||
@Resource
|
||||
private MapManage mapManage;
|
||||
@Override
|
||||
public void saveMapGeo(GeometryNodeCreator request, MultipartFile file) {
|
||||
mapManage.saveMapGeo(request, file);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteGeo(String id) {
|
||||
mapManage.deleteGeo(id);
|
||||
}
|
||||
}
|
@ -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,16 +2,21 @@ package io.dataease.system.manage;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import io.dataease.api.system.vo.SettingItemVO;
|
||||
import io.dataease.license.config.XpackInteract;
|
||||
import io.dataease.system.dao.auto.entity.CoreSysSetting;
|
||||
import io.dataease.system.dao.auto.mapper.CoreSysSettingMapper;
|
||||
import io.dataease.system.dao.ext.mapper.ExtCoreSysSettingMapper;
|
||||
import io.dataease.utils.BeanUtils;
|
||||
import io.dataease.utils.CommonBeanFactory;
|
||||
import io.dataease.utils.IDUtils;
|
||||
import io.dataease.utils.SystemSettingUtils;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
@ -71,26 +76,41 @@ public class SysParameterManage {
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<SettingItemVO> groupList(String groupKey) {
|
||||
public List<CoreSysSetting> groupList(String groupKey) {
|
||||
QueryWrapper<CoreSysSetting> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.likeRight("pkey", groupKey);
|
||||
queryWrapper.orderByAsc("sort");
|
||||
List<CoreSysSetting> sysSettings = coreSysSettingMapper.selectList(queryWrapper);
|
||||
if (!CollectionUtils.isEmpty(sysSettings)) {
|
||||
return sysSettings.stream().map(item -> BeanUtils.copyBean(new SettingItemVO(), item)).toList();
|
||||
}
|
||||
return null;
|
||||
return coreSysSettingMapper.selectList(queryWrapper);
|
||||
}
|
||||
|
||||
@XpackInteract(value = "perSetting")
|
||||
public List<SettingItemVO> convert(List<CoreSysSetting> sysSettings) {
|
||||
return sysSettings.stream().sorted(Comparator.comparing(CoreSysSetting::getSort)).map(item -> BeanUtils.copyBean(new SettingItemVO(), item)).toList();
|
||||
}
|
||||
|
||||
|
||||
@Transactional
|
||||
public void saveGroup(List<SettingItemVO> vos, String groupKey) {
|
||||
QueryWrapper<CoreSysSetting> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.likeRight("pkey", groupKey);
|
||||
coreSysSettingMapper.delete(queryWrapper);
|
||||
List<CoreSysSetting> sysSettings = vos.stream().map(item -> {
|
||||
List<CoreSysSetting> sysSettings = vos.stream().filter(vo -> !SystemSettingUtils.xpackSetting(vo.getPkey())).map(item -> {
|
||||
CoreSysSetting sysSetting = BeanUtils.copyBean(new CoreSysSetting(), item);
|
||||
sysSetting.setId(IDUtils.snowID());
|
||||
return sysSetting;
|
||||
}).collect(Collectors.toList());
|
||||
extCoreSysSettingMapper.saveBatch(sysSettings);
|
||||
}
|
||||
|
||||
|
||||
@XpackInteract(value = "perSetting", before = false)
|
||||
@Transactional
|
||||
public void saveBasic(List<SettingItemVO> vos) {
|
||||
String key = "basic.";
|
||||
proxy().saveGroup(vos, key);
|
||||
}
|
||||
|
||||
private SysParameterManage proxy() {
|
||||
return CommonBeanFactory.getBean(SysParameterManage.class);
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package io.dataease.system.server;
|
||||
import io.dataease.api.system.SysParameterApi;
|
||||
import io.dataease.api.system.request.OnlineMapEditor;
|
||||
import io.dataease.api.system.vo.SettingItemVO;
|
||||
import io.dataease.system.dao.auto.entity.CoreSysSetting;
|
||||
import io.dataease.system.manage.SysParameterManage;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@ -36,11 +37,12 @@ public class SysParameterServer implements SysParameterApi {
|
||||
@Override
|
||||
public List<SettingItemVO> queryBasicSetting() {
|
||||
String key = "basic.";
|
||||
return sysParameterManage.groupList(key);
|
||||
List<CoreSysSetting> coreSysSettings = sysParameterManage.groupList(key);
|
||||
return sysParameterManage.convert(coreSysSettings);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveBasicSetting(List<SettingItemVO> settingItemVOS) {
|
||||
sysParameterManage.saveGroup(settingItemVOS, "basic.");
|
||||
sysParameterManage.saveBasic(settingItemVOS);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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,18 +20,38 @@ 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;
|
||||
|
||||
DROP TABLE IF EXISTS `visualization_template_extend_data`;
|
||||
CREATE TABLE `visualization_template_extend_data` (
|
||||
`id` bigint NOT NULL,
|
||||
`dv_id` bigint DEFAULT NULL,
|
||||
`view_id` bigint DEFAULT NULL,
|
||||
`view_details` longtext,
|
||||
`copy_from` varchar(255) DEFAULT NULL,
|
||||
`copy_id` varchar(255) DEFAULT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
CREATE TABLE `visualization_template_extend_data`
|
||||
(
|
||||
`id` bigint NOT NULL,
|
||||
`dv_id` bigint DEFAULT NULL,
|
||||
`view_id` bigint DEFAULT NULL,
|
||||
`view_details` longtext,
|
||||
`copy_from` varchar(255) DEFAULT NULL,
|
||||
`copy_id` varchar(255) DEFAULT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
);
|
||||
|
||||
|
||||
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`;
|
||||
|
||||
DROP TABLE IF EXISTS `core_area_custom`;
|
||||
CREATE TABLE `core_area_custom`
|
||||
(
|
||||
`id` varchar(255) NOT NULL,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`pid` varchar(255) NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
);
|
||||
|
||||
BEGIN;
|
||||
INSERT INTO `core_sys_setting` VALUES (1, 'basic.dsIntervalTime', '6', 'text', 2);
|
||||
INSERT INTO `core_sys_setting` VALUES (2, 'basic.dsExecuteTime', 'minute', 'text', 3);
|
||||
COMMIT;
|
||||
|
@ -5,9 +5,21 @@ export const getWorldTree = (): Promise<IResponse<AreaNode>> => {
|
||||
return request.get({ url: '/map/worldTree' })
|
||||
}
|
||||
|
||||
export const getGeoJson = (
|
||||
country: string,
|
||||
areaId: string
|
||||
): Promise<IResponse<FeatureCollection>> => {
|
||||
return request.get({ url: `/map/${country}/${areaId}.json` })
|
||||
export const getGeoJson = (areaId: string): Promise<IResponse<FeatureCollection>> => {
|
||||
let prefix = '/map'
|
||||
let areaCode = areaId
|
||||
if (isCustomGeo(areaId)) {
|
||||
prefix = '/geo'
|
||||
areaCode = getBusiGeoCode(areaId)
|
||||
}
|
||||
const realCountry = areaCode.substring(0, 3)
|
||||
const url = `${prefix}/${realCountry}/${areaCode}.json`
|
||||
return request.get({ url })
|
||||
}
|
||||
|
||||
const isCustomGeo = (id: string) => {
|
||||
return id.startsWith('geo_')
|
||||
}
|
||||
const getBusiGeoCode = (id: string) => {
|
||||
return id.substring(4)
|
||||
}
|
||||
|
@ -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 |
@ -58,8 +58,7 @@ const loadComponent = () => {
|
||||
storeCacheProxy(byteArray)
|
||||
importProxy(byteArray)
|
||||
})
|
||||
.catch(e => {
|
||||
console.error(e)
|
||||
.catch(() => {
|
||||
showNolic()
|
||||
})
|
||||
.finally(() => {
|
||||
|
@ -130,7 +130,7 @@ service.interceptors.response.use(
|
||||
return response
|
||||
} else if (response.data.code === result_code || response.data.code === 50002) {
|
||||
return response.data
|
||||
} else if (response.config.url.match(/^\/map\/\d{3}\/\d+\.json$/)) {
|
||||
} else if (response.config.url.match(/^\/map|geo\/\d{3}\/\d+\.json$/)) {
|
||||
// TODO 处理静态文件
|
||||
return response
|
||||
} else {
|
||||
|
@ -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">
|
||||
|
@ -2122,5 +2122,10 @@ export default {
|
||||
geometry: '地理信息',
|
||||
onlinemap: '在线地图',
|
||||
empty_desc: '请在左侧输入信息然后保存'
|
||||
},
|
||||
setting_basic: {
|
||||
autoCreateUser: '禁止第三方自动创建用户',
|
||||
dsIntervalTime: '数据源检测时间间隔',
|
||||
dsExecuteTime: '数据源检测频率'
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ const license: F2CLicense = reactive({
|
||||
remark: '',
|
||||
isv: ''
|
||||
})
|
||||
const tipsSuffix = ref('')
|
||||
const build = ref('')
|
||||
const isAdmin = ref(false)
|
||||
const fileList = reactive([])
|
||||
@ -88,11 +89,14 @@ const validateHandler = (param, success) => {
|
||||
validateApi(param).then(success)
|
||||
}
|
||||
const getLicense = result => {
|
||||
if (result.status === 'valid') {
|
||||
tipsSuffix.value = result.edition === 'Embedded' ? '套' : '个账号'
|
||||
}
|
||||
return {
|
||||
status: result.status,
|
||||
corporation: result.license ? result.license.corporation : '',
|
||||
expired: result.license ? result.license.expired : '',
|
||||
count: result.license ? result.license.count : '',
|
||||
count: result.license ? result.license.count : 0,
|
||||
version: result.license ? result.license.version : '',
|
||||
edition: result.license ? result.license.edition : '',
|
||||
serialNo: result.license ? result.license.serialNo : '',
|
||||
@ -145,7 +149,9 @@ const update = (licKey: string) => {
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="label">{{ $t('about.auth_num') }}</div>
|
||||
<div class="value">{{ license.count }}</div>
|
||||
<div class="value">
|
||||
{{ license.status === 'valid' ? `${license.count} ${tipsSuffix}` : '' }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="label">{{ $t('about.version') }}</div>
|
||||
|
@ -421,10 +421,8 @@ export const getGeoJsonFile = async (areaId: string): Promise<FeatureCollection>
|
||||
const mapStore = useMapStoreWithOut()
|
||||
let geoJson = mapStore.mapCache[areaId]
|
||||
if (!geoJson) {
|
||||
const country = areaId.slice(0, 3)
|
||||
geoJson = await getGeoJson(country, areaId).then(result => {
|
||||
return result.data
|
||||
})
|
||||
const res = await getGeoJson(areaId)
|
||||
geoJson = res.data
|
||||
mapStore.setMap({ id: areaId, geoJson })
|
||||
}
|
||||
return toRaw(geoJson)
|
||||
|
@ -11,7 +11,7 @@
|
||||
<div class="info-template-content">
|
||||
<div class="info-content-item" v-for="item in settingList" :key="item.pkey">
|
||||
<div class="info-item-label">
|
||||
<span>{{ item.pkey }}</span>
|
||||
<span>{{ t(item.pkey) }}</span>
|
||||
<el-tooltip
|
||||
v-if="tooltipItem[item.pkey]"
|
||||
effect="dark"
|
||||
@ -33,7 +33,7 @@
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<span v-else-if="item.pkey === '数据源检测时间间隔'">
|
||||
<span v-else-if="item.pkey.includes('basic.dsIntervalTime')">
|
||||
<span>{{ item.pval + ' ' + executeTime + '执行一次' }}</span>
|
||||
</span>
|
||||
<span v-else>{{ item.pval }}</span>
|
||||
@ -74,7 +74,7 @@ const loadList = () => {
|
||||
settingList.value = []
|
||||
if (props.settingData?.length) {
|
||||
props.settingData.forEach(item => {
|
||||
if (item.pkey === '数据源检测频率') {
|
||||
if (item.pkey.includes('basic.dsExecuteTime')) {
|
||||
executeTime.value = getExecuteTime(item.pval)
|
||||
} else {
|
||||
settingList.value.push(item)
|
||||
@ -93,78 +93,6 @@ const getExecuteTime = val => {
|
||||
|
||||
const settingList = ref([] as SettingRecord[])
|
||||
|
||||
/* const loadBasic = () => {
|
||||
settingList.value.push({
|
||||
pkey: '请求超时时间',
|
||||
pval: '100',
|
||||
type: 'text',
|
||||
sort: 1
|
||||
})
|
||||
settingList.value.push({
|
||||
pkey: '数据源检测时间间隔',
|
||||
pval: '100',
|
||||
type: 'text',
|
||||
sort: 2
|
||||
})
|
||||
settingList.value.push({
|
||||
pkey: '默认登录方式',
|
||||
pval: '普通登录',
|
||||
type: 'text',
|
||||
sort: 3
|
||||
})
|
||||
settingList.value.push({
|
||||
pkey: '默认密码',
|
||||
pval: 'DataEase@123456',
|
||||
type: 'pwd',
|
||||
sort: 4
|
||||
})
|
||||
}
|
||||
|
||||
const loadEmail = () => {
|
||||
settingList.value.push({
|
||||
pkey: 'SMTP主机',
|
||||
pval: 'smtp.exmail.qq.com',
|
||||
type: 'text',
|
||||
sort: 1
|
||||
})
|
||||
settingList.value.push({
|
||||
pkey: 'SMTP端口',
|
||||
pval: '465',
|
||||
type: 'text',
|
||||
sort: 2
|
||||
})
|
||||
settingList.value.push({
|
||||
pkey: 'SMTP账户',
|
||||
pval: 'test@fit2cloud.com',
|
||||
type: 'text',
|
||||
sort: 3
|
||||
})
|
||||
settingList.value.push({
|
||||
pkey: 'SMTP密码',
|
||||
pval: 'DataEase@123456',
|
||||
type: 'pwd',
|
||||
sort: 4
|
||||
})
|
||||
settingList.value.push({
|
||||
pkey: '测试收件人',
|
||||
pval: 'yawen.chen@fit2cloud.com',
|
||||
type: 'pwd',
|
||||
sort: 5
|
||||
})
|
||||
settingList.value.push({
|
||||
pkey: 'SSL',
|
||||
pval: '开启',
|
||||
type: 'text',
|
||||
sort: 6
|
||||
})
|
||||
settingList.value.push({
|
||||
pkey: 'TSL',
|
||||
pval: '未开启',
|
||||
type: 'text',
|
||||
sort: 7
|
||||
})
|
||||
} */
|
||||
|
||||
const init = () => {
|
||||
if (props.settingData?.length) {
|
||||
loadList()
|
||||
|
@ -12,17 +12,12 @@ const options = [
|
||||
{ value: 'minute', label: '分钟(执行时间:0秒)' },
|
||||
{ value: 'hour', label: '小时(执行时间:0分0秒)' }
|
||||
]
|
||||
interface BasicFrom {
|
||||
autoCreateUser?: boolean
|
||||
dsIntervalTime?: string
|
||||
dsExecuteTime?: string
|
||||
}
|
||||
const state = reactive({
|
||||
form: reactive<BasicFrom>({
|
||||
autoCreateUser: false,
|
||||
form: reactive({
|
||||
dsIntervalTime: '30',
|
||||
dsExecuteTime: 'minute'
|
||||
})
|
||||
}),
|
||||
settingList: []
|
||||
})
|
||||
|
||||
const rule = reactive<FormRules>({
|
||||
@ -35,44 +30,24 @@ const rule = reactive<FormRules>({
|
||||
]
|
||||
})
|
||||
|
||||
const edit = row => {
|
||||
state.form = {
|
||||
autoCreateUser: row.autoCreateUser === 'true',
|
||||
dsIntervalTime: row.dsIntervalTime,
|
||||
dsExecuteTime: row.dsExecuteTime
|
||||
}
|
||||
dialogVisible.value = true
|
||||
}
|
||||
|
||||
const emits = defineEmits(['saved'])
|
||||
|
||||
const buildSettingList = () => {
|
||||
const param = { ...state.form }
|
||||
const item0 = {
|
||||
pkey: 'basic.autoCreateUser',
|
||||
pval: param.autoCreateUser.toString(),
|
||||
type: 'text',
|
||||
sort: 1
|
||||
}
|
||||
const item1 = {
|
||||
pkey: 'basic.dsIntervalTime',
|
||||
pval: param.dsIntervalTime,
|
||||
type: 'text',
|
||||
sort: 2
|
||||
}
|
||||
const item2 = {
|
||||
pkey: 'basic.dsExecuteTime',
|
||||
pval: param.dsExecuteTime,
|
||||
type: 'text',
|
||||
sort: 3
|
||||
}
|
||||
return [item0, item1, item2]
|
||||
return state.settingList.map(item => {
|
||||
const pkey = item.pkey.startsWith('basic.') ? item.pkey : `basic.${item.pkey}`
|
||||
const sort = item.sort
|
||||
const type = item.type
|
||||
const pval = state.form[item.pkey]
|
||||
return { pkey, pval, type, sort }
|
||||
})
|
||||
}
|
||||
const emits = defineEmits(['saved'])
|
||||
const submitForm = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
await formEl.validate((valid, fields) => {
|
||||
if (valid) {
|
||||
const param = buildSettingList()
|
||||
if (param.length < 2) {
|
||||
return
|
||||
}
|
||||
showLoading()
|
||||
request
|
||||
.post({ url: '/sysParameter/basic/save', data: param })
|
||||
@ -94,6 +69,7 @@ const submitForm = async (formEl: FormInstance | undefined) => {
|
||||
}
|
||||
|
||||
const resetForm = (formEl: FormInstance | undefined) => {
|
||||
state.settingList = []
|
||||
if (!formEl) return
|
||||
formEl.resetFields()
|
||||
dialogVisible.value = false
|
||||
@ -109,6 +85,19 @@ const showLoading = () => {
|
||||
const closeLoading = () => {
|
||||
loadingInstance.value?.close()
|
||||
}
|
||||
|
||||
const edit = list => {
|
||||
state.settingList = list.map(item => {
|
||||
const pkey = item.pkey
|
||||
item['label'] = `setting_${pkey}`
|
||||
item['pkey'] = pkey.split('.')[1]
|
||||
let pval = item.pval
|
||||
state.form[item['pkey']] = pval || state.form[item['pkey']]
|
||||
return item
|
||||
})
|
||||
console.log(state.settingList)
|
||||
dialogVisible.value = true
|
||||
}
|
||||
defineExpose({
|
||||
edit
|
||||
})
|
||||
@ -130,11 +119,48 @@ defineExpose({
|
||||
label-width="80px"
|
||||
label-position="top"
|
||||
>
|
||||
<el-form-item label="禁止扫码创建用户" prop="autoCreateUser">
|
||||
<el-switch v-model="state.form.autoCreateUser" />
|
||||
<el-form-item
|
||||
v-for="item in state.settingList"
|
||||
:key="item.pkey"
|
||||
:prop="item.pkey"
|
||||
:class="{ 'setting-hidden-item': item.pkey === 'dsExecuteTime' }"
|
||||
:label="t(item.label)"
|
||||
>
|
||||
<el-switch
|
||||
v-if="item.pkey === 'autoCreateUser'"
|
||||
active-value="true"
|
||||
inactive-value="false"
|
||||
v-model="state.form[item.pkey]"
|
||||
/>
|
||||
<div v-else-if="item.pkey === 'dsIntervalTime'" class="ds-task-form-inline">
|
||||
<span>每</span>
|
||||
<el-input-number
|
||||
v-model="state.form.dsIntervalTime"
|
||||
autocomplete="off"
|
||||
step-strictly
|
||||
class="text-left"
|
||||
:min="1"
|
||||
:placeholder="t('common.inputText')"
|
||||
controls-position="right"
|
||||
type="number"
|
||||
/>
|
||||
<el-select v-model="state.form.dsExecuteTime">
|
||||
<el-option
|
||||
v-for="item in options"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
<span class="ds-span">执行一次</span>
|
||||
</div>
|
||||
<div v-else />
|
||||
</el-form-item>
|
||||
<!-- <el-form-item label="禁止扫码创建用户" prop="autoCreateUser">
|
||||
<el-switch v-model="state.form.autoCreateUser" />
|
||||
</el-form-item> -->
|
||||
|
||||
<el-form-item label="数据源检测时间间隔" prop="dsIntervalTime">
|
||||
<!-- <el-form-item label="数据源检测时间间隔" prop="dsIntervalTime">
|
||||
<div class="ds-task-form-inline">
|
||||
<span>每</span>
|
||||
<el-input-number
|
||||
@ -157,7 +183,7 @@ defineExpose({
|
||||
</el-select>
|
||||
<span class="ds-span">执行一次</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form-item> -->
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
@ -171,6 +197,9 @@ defineExpose({
|
||||
</template>
|
||||
|
||||
<style scoped lang="less">
|
||||
.setting-hidden-item {
|
||||
display: none !important;
|
||||
}
|
||||
.ds-task-form-inline {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
|
@ -17,6 +17,7 @@ import BasicEdit from './BasicEdit.vue'
|
||||
import request from '@/config/axios'
|
||||
import { SettingRecord } from '@/views/system/common/SettingTemplate'
|
||||
import { reactive } from 'vue'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
const editor = ref()
|
||||
const infoTemplate = ref()
|
||||
const tooltips = [
|
||||
@ -26,39 +27,25 @@ const tooltips = [
|
||||
}
|
||||
]
|
||||
const state = reactive({
|
||||
templateList: [
|
||||
{
|
||||
pkey: '禁止扫码创建用户',
|
||||
pval: '未开启',
|
||||
type: 'text',
|
||||
sort: 1
|
||||
},
|
||||
{
|
||||
pkey: '数据源检测时间间隔',
|
||||
pval: '100',
|
||||
type: 'text',
|
||||
sort: 2
|
||||
},
|
||||
{
|
||||
pkey: '数据源检测频率',
|
||||
pval: 'minute',
|
||||
type: 'text',
|
||||
sort: 3
|
||||
}
|
||||
] as SettingRecord[]
|
||||
templateList: [] as SettingRecord[]
|
||||
})
|
||||
|
||||
let originData = []
|
||||
const search = cb => {
|
||||
const url = '/sysParameter/basic/query'
|
||||
originData = []
|
||||
state.templateList = []
|
||||
request.get({ url }).then(res => {
|
||||
originData = cloneDeep(res.data)
|
||||
const data = res.data
|
||||
for (let index = 0; index < data.length; index++) {
|
||||
const item = data[index]
|
||||
if (index === 0) {
|
||||
state.templateList[index].pval = item.pval === 'true' ? '开启' : '未开启'
|
||||
if (item.pkey === 'basic.autoCreateUser') {
|
||||
item.pval = item.pval === 'true' ? '开启' : '未开启'
|
||||
} else {
|
||||
state.templateList[index].pval = item.pval
|
||||
item.pval = item.pval
|
||||
}
|
||||
item.pkey = 'setting_' + item.pkey
|
||||
state.templateList.push(item)
|
||||
}
|
||||
cb && cb()
|
||||
})
|
||||
@ -68,14 +55,9 @@ const refresh = () => {
|
||||
infoTemplate?.value.init()
|
||||
})
|
||||
}
|
||||
search(null)
|
||||
refresh()
|
||||
|
||||
const edit = () => {
|
||||
const param = {
|
||||
autoCreateUser: state.templateList[0].pval === '开启' ? 'true' : 'false',
|
||||
dsIntervalTime: state.templateList[1].pval,
|
||||
dsExecuteTime: state.templateList[2].pval
|
||||
}
|
||||
editor?.value.edit(param)
|
||||
editor?.value.edit(cloneDeep(originData))
|
||||
}
|
||||
</script>
|
||||
|
@ -43,6 +43,19 @@
|
||||
:title="data.name"
|
||||
v-html="data.colorName && keyword ? data.colorName : data.name"
|
||||
/>
|
||||
<span class="geo-operate-container">
|
||||
<el-tooltip
|
||||
v-if="data.custom"
|
||||
class="box-item"
|
||||
effect="dark"
|
||||
:content="t('common.delete')"
|
||||
placement="top"
|
||||
>
|
||||
<el-icon @click.stop="delHandler(data)" class="hover-icon">
|
||||
<Icon name="icon_delete-trash_outlined"></Icon>
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</span>
|
||||
</span>
|
||||
</template>
|
||||
</el-tree>
|
||||
@ -83,7 +96,7 @@
|
||||
</div>
|
||||
</el-main>
|
||||
</el-container>
|
||||
<geometry-edit ref="editor" :tree-data="treeData" @saved="loadTreeData" />
|
||||
<geometry-edit ref="editor" @saved="loadTreeData(false)" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
@ -95,6 +108,10 @@ import { getGeoJsonFile } from '@/views/chart/components/js/util'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
import { setColorName } from '@/utils/utils'
|
||||
import GeometryEdit from './GeometryEdit.vue'
|
||||
import { useCache } from '@/hooks/web/useCache'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus-secondary'
|
||||
import request from '@/config/axios'
|
||||
const { wsCache } = useCache()
|
||||
const { t } = useI18n()
|
||||
const keyword = ref('')
|
||||
const treeData = ref([])
|
||||
@ -104,7 +121,7 @@ interface Tree {
|
||||
children?: Tree[]
|
||||
}
|
||||
const areaTreeRef = ref(null)
|
||||
|
||||
const loading = ref(false)
|
||||
const selectedData = ref(null)
|
||||
|
||||
const handleNodeClick = async (data: Tree) => {
|
||||
@ -119,6 +136,29 @@ const handleNodeClick = async (data: Tree) => {
|
||||
}
|
||||
}
|
||||
}
|
||||
const delHandler = data => {
|
||||
ElMessageBox.confirm('确定删除此节点吗', {
|
||||
confirmButtonType: 'danger',
|
||||
type: 'warning',
|
||||
confirmButtonText: t('common.delete'),
|
||||
cancelButtonText: t('dataset.cancel'),
|
||||
autofocus: false,
|
||||
showClose: false
|
||||
})
|
||||
.then(() => {
|
||||
const url = '/geometry/delete/' + data.id
|
||||
request.post({ url }).then(() => {
|
||||
if (selectedData.value?.id === data.id) {
|
||||
selectedData.value = null
|
||||
}
|
||||
ElMessage.success(t('common.delete_success'))
|
||||
loadTreeData(false)
|
||||
})
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
const filterResource = val => {
|
||||
areaTreeRef.value?.filter(val)
|
||||
}
|
||||
@ -128,11 +168,18 @@ const filterResourceNode = (value: string, data) => {
|
||||
return data.name.toLocaleLowerCase().includes(value.toLocaleLowerCase())
|
||||
}
|
||||
|
||||
const loadTreeData = () => {
|
||||
const loadTreeData = (cache?: boolean) => {
|
||||
const key = 'de-area-tree'
|
||||
const result = wsCache.get(key)
|
||||
if (result && cache) {
|
||||
treeData.value = result
|
||||
return
|
||||
}
|
||||
getWorldTree()
|
||||
.then(res => {
|
||||
const root = res.data
|
||||
treeData.value = [root]
|
||||
wsCache.set(key, treeData.value)
|
||||
})
|
||||
.catch(e => {
|
||||
console.error(e)
|
||||
@ -143,7 +190,7 @@ const add = (pid?: string) => {
|
||||
editor?.value.edit(pid)
|
||||
}
|
||||
|
||||
loadTreeData()
|
||||
loadTreeData(true)
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@ -165,7 +212,6 @@ loadTreeData()
|
||||
line-height: 24px;
|
||||
}
|
||||
.add-icon-span {
|
||||
// display: none;
|
||||
color: #3370ff;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
@ -257,5 +303,16 @@ loadTreeData()
|
||||
box-sizing: content-box;
|
||||
padding-right: 4px;
|
||||
overflow: hidden;
|
||||
justify-content: space-between;
|
||||
|
||||
.geo-operate-container {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.geo-operate-container {
|
||||
display: contents;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive, PropType } from 'vue'
|
||||
import { ref, reactive } from 'vue'
|
||||
import { ElMessage, ElLoading } from 'element-plus-secondary'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import type {
|
||||
@ -10,16 +10,12 @@ import type {
|
||||
} from 'element-plus-secondary'
|
||||
import request from '@/config/axios'
|
||||
import { GeometryFrom } from './interface'
|
||||
import { useCache } from '@/hooks/web/useCache'
|
||||
const { wsCache } = useCache()
|
||||
const { t } = useI18n()
|
||||
const dialogVisible = ref(false)
|
||||
const loadingInstance = ref(null)
|
||||
const geoForm = ref<FormInstance>()
|
||||
const props = defineProps({
|
||||
treeData: {
|
||||
type: Array as PropType<unknown[]>,
|
||||
default: () => []
|
||||
}
|
||||
})
|
||||
const geoFile = ref()
|
||||
const fileName = ref()
|
||||
const state = reactive({
|
||||
@ -27,7 +23,8 @@ const state = reactive({
|
||||
pid: null,
|
||||
code: null,
|
||||
name: null
|
||||
})
|
||||
}),
|
||||
treeData: []
|
||||
})
|
||||
const treeProps = {
|
||||
value: 'id',
|
||||
@ -60,6 +57,8 @@ const rule = reactive<FormRules>({
|
||||
})
|
||||
|
||||
const edit = (pid?: string) => {
|
||||
const key = 'de-area-tree'
|
||||
state.treeData = wsCache.get(key)
|
||||
state.form.pid = pid
|
||||
state.form.code = null
|
||||
state.form.name = null
|
||||
@ -75,9 +74,10 @@ const submitForm = async (formEl: FormInstance | undefined) => {
|
||||
await formEl.validate((valid, fields) => {
|
||||
if (valid) {
|
||||
const param = { ...state.form }
|
||||
const formData = buildFormData(geoFile.value, param)
|
||||
showLoading()
|
||||
request
|
||||
.post({ url: '/sysParameter/map/save', data: param })
|
||||
.post({ url: '/geometry/save', data: formData, headersType: 'multipart/form-data;' })
|
||||
.then(res => {
|
||||
if (!res.msg) {
|
||||
ElMessage.success(t('common.save_success'))
|
||||
@ -136,6 +136,14 @@ const uploadValidate = file => {
|
||||
}
|
||||
return true
|
||||
}
|
||||
const buildFormData = (file, param) => {
|
||||
const formData = new FormData()
|
||||
if (file) {
|
||||
formData.append('file', file)
|
||||
}
|
||||
formData.append('request', new Blob([JSON.stringify(param)], { type: 'application/json' }))
|
||||
return formData
|
||||
}
|
||||
defineExpose({
|
||||
edit
|
||||
})
|
||||
@ -163,7 +171,7 @@ defineExpose({
|
||||
node-key="id"
|
||||
v-model="state.form.pid"
|
||||
:props="treeProps"
|
||||
:data="props.treeData"
|
||||
:data="state.treeData"
|
||||
check-strictly
|
||||
:render-after-expand="false"
|
||||
:placeholder="t('common.please_select')"
|
||||
|
@ -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
de-xpack
2
de-xpack
@ -1 +1 @@
|
||||
Subproject commit 723bb9ff960159769673ac58982f07b18e6aa181
|
||||
Subproject commit e31c9212056eae3656aa534e3cc778d00001fe98
|
@ -66,6 +66,7 @@ curl http://127.0.0.1:9180/apisix/admin/services/10 -X PUT -H "X-API-KEY: $DE_AP
|
||||
"X-DE-TOKEN",
|
||||
"X-DE-LINK-TOKEN",
|
||||
"X-EMBEDDED-TOKEN",
|
||||
"X-DE-ASK-TOKEN",
|
||||
"Content-Type"
|
||||
],
|
||||
"request_method": "POST",
|
||||
|
@ -11,6 +11,7 @@ services:
|
||||
- ${DE_BASE}/dataease2.0/logs:/opt/dataease2.0/logs
|
||||
- ${DE_BASE}/dataease2.0/data/static-resource:/opt/dataease2.0/data/static-resource
|
||||
- ${DE_BASE}/dataease2.0/cache:/opt/dataease2.0/cache
|
||||
- ${DE_BASE}/dataease2.0/data/geo:/opt/dataease2.0/data/geo
|
||||
depends_on:
|
||||
DE_MYSQL_HOST:
|
||||
condition: service_healthy
|
||||
|
@ -11,7 +11,6 @@ spring:
|
||||
username: ${DE_MYSQL_USER}
|
||||
password: ${DE_MYSQL_PASSWORD}
|
||||
dataease:
|
||||
origin-list: localhost:8080,localhost:8100,localhost:9080
|
||||
apisix-api:
|
||||
domain: http://apisix:9180
|
||||
key: DE_APISIX_KEY
|
2
pom.xml
2
pom.xml
@ -25,7 +25,7 @@
|
||||
<mybatis-plus.version>3.5.3.1</mybatis-plus.version>
|
||||
<h2.version>1.4.199</h2.version>
|
||||
<knife4j.version>4.1.0</knife4j.version>
|
||||
<calcite-core.version>1.35.0</calcite-core.version>
|
||||
<calcite-core.version>1.36.0</calcite-core.version>
|
||||
<commons-dbcp2.version>2.6.0</commons-dbcp2.version>
|
||||
<antlr.version>3.5.2</antlr.version>
|
||||
<java-jwt.version>3.12.1</java-jwt.version>
|
||||
|
@ -0,0 +1,18 @@
|
||||
package io.dataease.api.map;
|
||||
|
||||
import io.dataease.api.map.dto.GeometryNodeCreator;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestPart;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
@Tag(name = "地理信息")
|
||||
public interface GeoApi {
|
||||
|
||||
@PostMapping(value = "/save", consumes = {"multipart/form-data"})
|
||||
void saveMapGeo(@RequestPart("request") GeometryNodeCreator request, @RequestPart(value = "file") MultipartFile file);
|
||||
|
||||
@PostMapping("/delete/{id}")
|
||||
void deleteGeo(@PathVariable("id") String id);
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package io.dataease.api.map.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
public class GeometryNodeCreator implements Serializable {
|
||||
|
||||
private String code;
|
||||
|
||||
private String name;
|
||||
|
||||
private String pid;
|
||||
}
|
@ -18,6 +18,7 @@ public class AreaNode implements Serializable {
|
||||
private String level;
|
||||
private String name;
|
||||
private String pid;
|
||||
private boolean custom = false;
|
||||
/**
|
||||
* 国家代码
|
||||
*/
|
||||
|
@ -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;
|
||||
|
@ -0,0 +1,25 @@
|
||||
package io.dataease.api.permissions.apikey.api;
|
||||
|
||||
import io.dataease.api.permissions.apikey.dto.ApikeyEnableEditor;
|
||||
import io.dataease.api.permissions.apikey.vo.ApiKeyVO;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ApiKeyApi {
|
||||
|
||||
@PostMapping("/generate")
|
||||
void generate();
|
||||
|
||||
@GetMapping("/query")
|
||||
List<ApiKeyVO> query();
|
||||
|
||||
@PostMapping("/switch")
|
||||
void switchEnable(@RequestBody ApikeyEnableEditor editor);
|
||||
|
||||
@PostMapping("/delete/{id}")
|
||||
void delete(@PathVariable("id") Long id);
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package io.dataease.api.permissions.apikey.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
public class ApikeyEnableEditor implements Serializable {
|
||||
|
||||
private Long id;
|
||||
|
||||
private Boolean enable = false;
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package io.dataease.api.permissions.apikey.vo;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
public class ApiKeyVO implements Serializable {
|
||||
|
||||
@JsonSerialize(using= ToStringSerializer.class)
|
||||
private Long id;
|
||||
|
||||
private String accessKey;
|
||||
|
||||
private String accessSecret;
|
||||
|
||||
private Boolean enable;
|
||||
|
||||
private Long createTime;
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package io.dataease.api.permissions.setting.api;
|
||||
|
||||
import io.dataease.api.permissions.setting.vo.PerSettingItemVO;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface PerSettingApi {
|
||||
|
||||
@GetMapping("/basic/query")
|
||||
List<PerSettingItemVO> basicSetting();
|
||||
|
||||
@PostMapping("/baisc/save")
|
||||
void saveBasic(@RequestBody List<Object> settings);
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package io.dataease.api.permissions.setting.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class PerSettingItemVO implements Serializable {
|
||||
|
||||
private String pkey;
|
||||
|
||||
private String pval;
|
||||
|
||||
private String type;
|
||||
|
||||
private Integer sort;
|
||||
}
|
@ -18,6 +18,7 @@ public class AuthConstant {
|
||||
public final static String USER_IMPORT_ERROR_KEY = "USER-IMPORT-ERROR-KEY";
|
||||
|
||||
public final static String LINK_TOKEN_KEY = "X-DE-LINK-TOKEN";
|
||||
public final static String ASK_TOKEN_KEY = "X-DE-ASK-TOKEN";
|
||||
|
||||
public final static String DE_EXECUTE_VERSION = "X-DE-EXECUTE-VERSION";
|
||||
|
||||
|
@ -16,8 +16,10 @@ public class StaticResourceConstants {
|
||||
public static String WORK_DIR = ensureSuffix(USER_HOME, FILE_SEPARATOR) + "static-resource" + FILE_SEPARATOR;
|
||||
|
||||
public static String MAP_DIR = ensureSuffix(USER_HOME, FILE_SEPARATOR) + "map";
|
||||
public static String CUSTOM_MAP_DIR = ensureSuffix(USER_HOME, FILE_SEPARATOR) + "geo";
|
||||
|
||||
public static String MAP_URL = "/map";
|
||||
public static String GEO_URL = "/geo";
|
||||
|
||||
/**
|
||||
* Upload prefix.
|
||||
|
@ -0,0 +1,6 @@
|
||||
package io.dataease.constant;
|
||||
|
||||
public class XpackSettingConstants {
|
||||
|
||||
public static final String AUTO_CREATE_USER = "basic.autoCreateUser";
|
||||
}
|
36
sdk/common/src/main/java/io/dataease/utils/AesUtils.java
Normal file
36
sdk/common/src/main/java/io/dataease/utils/AesUtils.java
Normal file
@ -0,0 +1,36 @@
|
||||
package io.dataease.utils;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import javax.crypto.BadPaddingException;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.IllegalBlockSizeException;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
public class AesUtils {
|
||||
|
||||
public static String aesDecrypt(String src, String secretKey, String iv) {
|
||||
if (StringUtils.isBlank(secretKey)) {
|
||||
throw new RuntimeException("secretKey is empty");
|
||||
}
|
||||
try {
|
||||
byte[] raw = secretKey.getBytes(UTF_8);
|
||||
SecretKeySpec secretKeySpec = new SecretKeySpec(raw, "AES");
|
||||
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
|
||||
IvParameterSpec iv1 = new IvParameterSpec(iv.getBytes());
|
||||
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, iv1);
|
||||
byte[] encrypted1 = Base64.decodeBase64(src);
|
||||
byte[] original = cipher.doFinal(encrypted1);
|
||||
return new String(original, UTF_8);
|
||||
} catch (BadPaddingException | IllegalBlockSizeException e) {
|
||||
// 解密的原字符串为非加密字符串,则直接返回原字符串
|
||||
return src;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("decrypt error,please check parameters", e);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package io.dataease.utils;
|
||||
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import io.dataease.constant.XpackSettingConstants;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class SystemSettingUtils {
|
||||
|
||||
public static boolean xpackSetting(String pkey) {
|
||||
List<String> xpackSettingList = ListUtil.toList(XpackSettingConstants.AUTO_CREATE_USER);
|
||||
return xpackSettingList.contains(pkey);
|
||||
}
|
||||
}
|
@ -36,7 +36,7 @@ public class WhitelistUtils {
|
||||
|| StringUtils.startsWithAny(requestURI, "/static-resource/")
|
||||
|| StringUtils.startsWithAny(requestURI, "/share/proxyInfo")
|
||||
|| StringUtils.startsWithAny(requestURI, "/xpackComponent/content/")
|
||||
|| StringUtils.startsWithAny(requestURI, "/platform/")
|
||||
|| StringUtils.startsWithAny(requestURI, "/geo/")
|
||||
|| StringUtils.startsWithAny(requestURI, "/map/");
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user