forked from github/dataease
Merge branch 'dev-v2' into pr@dev-v2_dzz
This commit is contained in:
commit
a888a09cd0
@ -2,9 +2,9 @@ FROM registry.cn-qingdao.aliyuncs.com/dataease/alpine-openjdk17-jre
|
||||
|
||||
ARG IMAGE_TAG
|
||||
|
||||
RUN mkdir -p /opt/apps/config /opt/dataease/drivers/ /opt/dataease2.0/cache/ /opt/dataease2.0/data/map /opt/dataease2.0/data/static-resource/
|
||||
RUN mkdir -p /opt/apps/config /opt/dataease2.0/drivers/ /opt/dataease2.0/cache/ /opt/dataease2.0/data/map /opt/dataease2.0/data/static-resource/
|
||||
|
||||
ADD drivers/* /opt/dataease/drivers/
|
||||
ADD drivers/* /opt/dataease2.0/drivers/
|
||||
ADD mapFiles/ /opt/dataease2.0/data/map/
|
||||
ADD staticResource/ /opt/dataease2.0/data/static-resource/
|
||||
|
||||
|
11
README.md
11
README.md
@ -15,7 +15,9 @@
|
||||
|
||||
DataEase 是开源的数据可视化分析工具,帮助用户快速分析数据并洞察业务趋势,从而实现业务的改进与优化。DataEase 支持丰富的数据源连接,能够通过拖拉拽方式快速制作图表,并可以方便的与他人分享。
|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
|
||||
**DataEase 的优势:**
|
||||
|
||||
@ -52,11 +54,8 @@ DataEase 是开源的数据可视化分析工具,帮助用户快速分析数
|
||||
|
||||
## DataEase 快速入门
|
||||
|
||||
- [安装部署教程](https://dataease.io/docs/installation/installation_mode/)
|
||||
- [快速入门视频](https://www.bilibili.com/video/BV1qG4y1F7uc/)
|
||||
- [完整在线文档](https://dataease.io/docs/)
|
||||
- [中文社区论坛](https://bbs.fit2cloud.com/c/de/6)
|
||||
- [模板应用市场](https://dataease.io/templates/)
|
||||
- [在线文档](https://dataease.io/docs/)
|
||||
- [社区论坛](https://bbs.fit2cloud.com/c/de/6)
|
||||
|
||||
## License
|
||||
|
||||
|
@ -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://39.98.78.97: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";
|
||||
|
||||
/**
|
||||
* 业务模块例如datasource,dataset,panel等
|
||||
*/
|
||||
private static final String busi = "system";
|
||||
private static final String busi = "template";
|
||||
/**
|
||||
* 这是要生成代码的表名称
|
||||
*/
|
||||
private static final String TABLE_NAME = "core_sys_setting";
|
||||
private static final String TABLE_NAME = "visualization_template";
|
||||
|
||||
/**
|
||||
* 下面两个配置基本上不用动
|
||||
|
@ -1,14 +1,12 @@
|
||||
package io.dataease.chart.manage;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import io.dataease.api.chart.dto.*;
|
||||
import io.dataease.api.chart.request.ChartDrillRequest;
|
||||
import io.dataease.api.chart.request.ChartExtRequest;
|
||||
import io.dataease.api.dataset.dto.SqlVariableDetails;
|
||||
import io.dataease.api.dataset.union.DatasetGroupInfoDTO;
|
||||
import io.dataease.api.dataset.union.model.SQLMeta;
|
||||
import io.dataease.api.permissions.auth.api.InteractiveAuthApi;
|
||||
import io.dataease.api.permissions.auth.dto.BusiPerCheckDTO;
|
||||
import io.dataease.api.permissions.dataset.dto.DataSetRowPermissionsTreeDTO;
|
||||
import io.dataease.chart.constant.ChartConstants;
|
||||
@ -30,6 +28,7 @@ import io.dataease.engine.utils.Utils;
|
||||
import io.dataease.exception.DEException;
|
||||
import io.dataease.i18n.Translator;
|
||||
import io.dataease.result.ResultCode;
|
||||
import io.dataease.system.manage.CorePermissionManage;
|
||||
import io.dataease.utils.BeanUtils;
|
||||
import io.dataease.utils.JsonUtil;
|
||||
import jakarta.annotation.Resource;
|
||||
@ -37,7 +36,6 @@ import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
@ -65,8 +63,9 @@ public class ChartDataManage {
|
||||
private ChartViewManege chartViewManege;
|
||||
@Resource
|
||||
private PermissionManage permissionManage;
|
||||
@Autowired(required = false)
|
||||
private InteractiveAuthApi interactiveAuthApi;
|
||||
|
||||
@Resource
|
||||
private CorePermissionManage corePermissionManage;
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(ChartDataManage.class);
|
||||
|
||||
@ -140,11 +139,12 @@ public class ChartDataManage {
|
||||
DEException.throwException(ResultCode.DATA_IS_WRONG.code(), Translator.get("i18n_no_ds"));
|
||||
}
|
||||
// check permission
|
||||
if (interactiveAuthApi != null) {
|
||||
BusiPerCheckDTO dto = new BusiPerCheckDTO();
|
||||
dto.setId(table.getId());
|
||||
dto.setAuthEnum(AuthEnum.READ);
|
||||
interactiveAuthApi.checkAuth(dto);
|
||||
BusiPerCheckDTO dto = new BusiPerCheckDTO();
|
||||
dto.setId(table.getId());
|
||||
dto.setAuthEnum(AuthEnum.READ);
|
||||
boolean checked = corePermissionManage.checkAuth(dto);
|
||||
if (!checked) {
|
||||
DEException.throwException(Translator.get("i18n_no_datasource_permission"));
|
||||
}
|
||||
|
||||
// column permission
|
||||
|
@ -9,8 +9,6 @@ import io.dataease.api.dataset.union.DatasetGroupInfoDTO;
|
||||
import io.dataease.api.dataset.union.UnionDTO;
|
||||
import io.dataease.api.dataset.vo.DataSetBarVO;
|
||||
import io.dataease.api.ds.vo.DatasourceDTO;
|
||||
import io.dataease.api.permissions.user.api.UserApi;
|
||||
import io.dataease.api.permissions.user.vo.UserFormVO;
|
||||
import io.dataease.commons.constants.OptConstants;
|
||||
import io.dataease.dataset.dao.auto.entity.CoreDatasetGroup;
|
||||
import io.dataease.dataset.dao.auto.entity.CoreDatasetTable;
|
||||
@ -31,11 +29,11 @@ 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.system.manage.CoreUserManage;
|
||||
import io.dataease.utils.*;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@ -68,8 +66,10 @@ public class DatasetGroupManage {
|
||||
private CoreDatasetTableMapper coreDatasetTableMapper;
|
||||
@Resource
|
||||
private CoreDatasourceMapper coreDatasourceMapper;
|
||||
@Autowired(required = false)
|
||||
private UserApi userApi;
|
||||
|
||||
|
||||
@Resource
|
||||
private CoreUserManage coreUserManage;
|
||||
|
||||
@Resource
|
||||
private CoreOptRecentManage coreOptRecentManage;
|
||||
@ -88,13 +88,9 @@ public class DatasetGroupManage {
|
||||
CoreDatasetGroup coreDatasetGroup = coreDatasetGroupMapper.selectById(datasetGroupInfoDTO.getId());
|
||||
datasetGroupInfoDTO.setPid(coreDatasetGroup.getPid());
|
||||
}
|
||||
if (userApi == null) {
|
||||
checkName(datasetGroupInfoDTO);
|
||||
}
|
||||
if (userApi != null) {
|
||||
datasetGroupInfoDTO.setUpdateBy(userApi.info().getId() + "");
|
||||
datasetGroupInfoDTO.setLastUpdateTime(System.currentTimeMillis());
|
||||
}
|
||||
checkName(datasetGroupInfoDTO);
|
||||
datasetGroupInfoDTO.setUpdateBy(AuthUtils.getUser().getUserId() + "");
|
||||
datasetGroupInfoDTO.setLastUpdateTime(System.currentTimeMillis());
|
||||
if (StringUtils.equalsIgnoreCase(datasetGroupInfoDTO.getNodeType(), leafType)) {
|
||||
if (!rename && ObjectUtils.isEmpty(datasetGroupInfoDTO.getAllFields())) {
|
||||
DEException.throwException(Translator.get("i18n_no_fields"));
|
||||
@ -112,10 +108,8 @@ public class DatasetGroupManage {
|
||||
if (ObjectUtils.isEmpty(datasetGroupInfoDTO.getId())) {
|
||||
isCreate = true;
|
||||
datasetGroupInfoDTO.setId(IDUtils.snowID());
|
||||
if (userApi != null) {
|
||||
datasetGroupInfoDTO.setCreateBy(userApi.info().getId() + "");
|
||||
datasetGroupInfoDTO.setUpdateBy(userApi.info().getId() + "");
|
||||
}
|
||||
datasetGroupInfoDTO.setCreateBy(AuthUtils.getUser().getUserId() + "");
|
||||
datasetGroupInfoDTO.setUpdateBy(AuthUtils.getUser().getUserId() + "");
|
||||
datasetGroupInfoDTO.setCreateTime(time);
|
||||
datasetGroupInfoDTO.setLastUpdateTime(time);
|
||||
datasetGroupInfoDTO.setPid(datasetGroupInfoDTO.getPid() == null ? 0L : datasetGroupInfoDTO.getPid());
|
||||
@ -152,21 +146,19 @@ public class DatasetGroupManage {
|
||||
CoreDatasetGroup coreDatasetGroup = BeanUtils.copyBean(new CoreDatasetGroup(), datasetGroupInfoDTO);
|
||||
coreDatasetGroup.setLastUpdateTime(System.currentTimeMillis());
|
||||
coreDatasetGroupMapper.updateById(coreDatasetGroup);
|
||||
coreOptRecentManage.saveOpt(datasetGroupInfoDTO.getId(), OptConstants.OPT_RESOURCE_TYPE.DATASET,OptConstants.OPT_TYPE.UPDATE);
|
||||
coreOptRecentManage.saveOpt(datasetGroupInfoDTO.getId(), OptConstants.OPT_RESOURCE_TYPE.DATASET, OptConstants.OPT_TYPE.UPDATE);
|
||||
}
|
||||
|
||||
@XpackInteract(value = "authResourceTree", before = false)
|
||||
public void innerSave(DatasetGroupInfoDTO datasetGroupInfoDTO) {
|
||||
CoreDatasetGroup coreDatasetGroup = BeanUtils.copyBean(new CoreDatasetGroup(), datasetGroupInfoDTO);
|
||||
coreDatasetGroupMapper.insert(coreDatasetGroup);
|
||||
coreOptRecentManage.saveOpt(coreDatasetGroup.getId(), OptConstants.OPT_RESOURCE_TYPE.DATASET,OptConstants.OPT_TYPE.NEW);
|
||||
coreOptRecentManage.saveOpt(coreDatasetGroup.getId(), OptConstants.OPT_RESOURCE_TYPE.DATASET, OptConstants.OPT_TYPE.NEW);
|
||||
}
|
||||
|
||||
@XpackInteract(value = "authResourceTree", before = false)
|
||||
public DatasetGroupInfoDTO move(DatasetGroupInfoDTO datasetGroupInfoDTO) {
|
||||
if (userApi == null) {
|
||||
checkName(datasetGroupInfoDTO);
|
||||
}
|
||||
checkName(datasetGroupInfoDTO);
|
||||
if (datasetGroupInfoDTO.getPid() != 0) {
|
||||
checkMove(datasetGroupInfoDTO);
|
||||
}
|
||||
@ -174,12 +166,10 @@ public class DatasetGroupManage {
|
||||
long time = System.currentTimeMillis();
|
||||
CoreDatasetGroup coreDatasetGroup = new CoreDatasetGroup();
|
||||
BeanUtils.copyBean(coreDatasetGroup, datasetGroupInfoDTO);
|
||||
if (userApi != null) {
|
||||
datasetGroupInfoDTO.setUpdateBy(userApi.info().getId() + "");
|
||||
}
|
||||
datasetGroupInfoDTO.setUpdateBy(AuthUtils.getUser().getUserId() + "");
|
||||
coreDatasetGroup.setLastUpdateTime(time);
|
||||
coreDatasetGroupMapper.updateById(coreDatasetGroup);
|
||||
coreOptRecentManage.saveOpt(coreDatasetGroup.getId(), OptConstants.OPT_RESOURCE_TYPE.DATASET,OptConstants.OPT_TYPE.UPDATE);
|
||||
coreOptRecentManage.saveOpt(coreDatasetGroup.getId(), OptConstants.OPT_RESOURCE_TYPE.DATASET, OptConstants.OPT_TYPE.UPDATE);
|
||||
return datasetGroupInfoDTO;
|
||||
}
|
||||
|
||||
@ -190,7 +180,7 @@ public class DatasetGroupManage {
|
||||
DEException.throwException("resource not exist");
|
||||
}
|
||||
Objects.requireNonNull(CommonBeanFactory.getBean(this.getClass())).recursionDel(id);
|
||||
coreOptRecentManage.saveOpt(coreDatasetGroup.getId(), OptConstants.OPT_RESOURCE_TYPE.DATASET,OptConstants.OPT_TYPE.DELETE);
|
||||
coreOptRecentManage.saveOpt(coreDatasetGroup.getId(), OptConstants.OPT_RESOURCE_TYPE.DATASET, OptConstants.OPT_TYPE.DELETE);
|
||||
}
|
||||
|
||||
public void recursionDel(Long id) {
|
||||
@ -231,15 +221,13 @@ public class DatasetGroupManage {
|
||||
public DataSetBarVO queryBarInfo(Long id) {
|
||||
DataSetBarVO dataSetBarVO = coreDataSetExtMapper.queryBarInfo(id);
|
||||
// get creator
|
||||
if (userApi != null) {
|
||||
UserFormVO userFormVO = userApi.queryById(Long.valueOf(dataSetBarVO.getCreateBy()));
|
||||
if (userFormVO != null) {
|
||||
dataSetBarVO.setCreator(userFormVO.getName());
|
||||
}
|
||||
UserFormVO userFormVOUpdateBy = userApi.queryById(Long.valueOf(dataSetBarVO.getUpdateBy()));
|
||||
if (userFormVOUpdateBy != null) {
|
||||
dataSetBarVO.setUpdater(userFormVOUpdateBy.getName());
|
||||
}
|
||||
String userName = coreUserManage.getUserName(Long.valueOf(dataSetBarVO.getCreateBy()));
|
||||
if (StringUtils.isNotBlank(userName)) {
|
||||
dataSetBarVO.setCreator(userName);
|
||||
}
|
||||
String updateUserName = coreUserManage.getUserName(Long.valueOf(dataSetBarVO.getUpdateBy()));
|
||||
if (StringUtils.isNotBlank(updateUserName)) {
|
||||
dataSetBarVO.setUpdater(updateUserName);
|
||||
}
|
||||
dataSetBarVO.setDatasourceDTOList(getDatasource(id));
|
||||
return dataSetBarVO;
|
||||
@ -254,13 +242,13 @@ public class DatasetGroupManage {
|
||||
|
||||
QueryWrapper<CoreDatasource> datasourceQueryWrapper = new QueryWrapper<>();
|
||||
datasourceQueryWrapper.in("id", ids);
|
||||
List<DatasourceDTO> datasourceDTOList = coreDatasourceMapper.selectList(datasourceQueryWrapper).stream().map(ele -> {
|
||||
List<DatasourceDTO> datasourceDTOList = coreDatasourceMapper.selectList(datasourceQueryWrapper).stream().map(ele -> {
|
||||
DatasourceDTO dto = new DatasourceDTO();
|
||||
BeanUtils.copyBean(dto, ele);
|
||||
dto.setConfiguration(null);
|
||||
return dto;
|
||||
}).collect(Collectors.toList());
|
||||
if(ids.size() != datasourceDTOList.size()){
|
||||
if (ids.size() != datasourceDTOList.size()) {
|
||||
DEException.throwException("由于数据集所用的数据源已被删除,无法显示数据集");
|
||||
}
|
||||
return datasourceDTOList;
|
||||
@ -366,15 +354,13 @@ public class DatasetGroupManage {
|
||||
DatasetGroupInfoDTO dto = new DatasetGroupInfoDTO();
|
||||
BeanUtils.copyBean(dto, coreDatasetGroup);
|
||||
// get creator
|
||||
if (userApi != null) {
|
||||
UserFormVO userFormVO = userApi.queryById(Long.valueOf(dto.getCreateBy()));
|
||||
if (userFormVO != null) {
|
||||
dto.setCreator(userFormVO.getName());
|
||||
}
|
||||
UserFormVO userFormVOUpdateBy = userApi.queryById(Long.valueOf(dto.getUpdateBy()));
|
||||
if (userFormVOUpdateBy != null) {
|
||||
dto.setUpdater(userFormVOUpdateBy.getName());
|
||||
}
|
||||
String userName = coreUserManage.getUserName(Long.valueOf(dto.getCreateBy()));
|
||||
if (StringUtils.isNotBlank(userName)) {
|
||||
dto.setCreator(userName);
|
||||
}
|
||||
String updateUserName = coreUserManage.getUserName(Long.valueOf(dto.getUpdateBy()));
|
||||
if (StringUtils.isNotBlank(updateUserName)) {
|
||||
dto.setUpdater(updateUserName);
|
||||
}
|
||||
dto.setUnionSql(null);
|
||||
if (StringUtils.equalsIgnoreCase(dto.getNodeType(), "dataset")) {
|
||||
@ -440,8 +426,8 @@ public class DatasetGroupManage {
|
||||
for (CoreDatasetTable datasetTable : datasetTables) {
|
||||
if (StringUtils.isNotEmpty(datasetTable.getSqlVariableDetails())) {
|
||||
List<SqlVariableDetails> defaultsSqlVariableDetails = JsonUtil.parseList(datasetTable.getSqlVariableDetails(), listTypeReference);
|
||||
if(CollectionUtil.isNotEmpty(defaultsSqlVariableDetails)){
|
||||
List<String> fullName = new ArrayList<>();
|
||||
if (CollectionUtil.isNotEmpty(defaultsSqlVariableDetails)) {
|
||||
List<String> fullName = new ArrayList<>();
|
||||
geFullName(id, fullName);
|
||||
List<String> finalFullName = CollectionUtil.reverse(fullName);
|
||||
defaultsSqlVariableDetails.forEach(sqlVariableDetails -> {
|
||||
|
@ -6,12 +6,10 @@ import io.dataease.api.dataset.dto.DatasetTableDTO;
|
||||
import io.dataease.api.dataset.dto.SqlVariableDetails;
|
||||
import io.dataease.api.dataset.union.*;
|
||||
import io.dataease.api.dataset.union.model.SQLObj;
|
||||
import io.dataease.api.permissions.auth.api.InteractiveAuthApi;
|
||||
import io.dataease.api.permissions.auth.dto.BusiPerCheckDTO;
|
||||
import io.dataease.commons.utils.SqlparserUtils;
|
||||
import io.dataease.constant.AuthEnum;
|
||||
import io.dataease.dataset.constant.DatasetTableType;
|
||||
import io.dataease.dataset.dao.auto.mapper.CoreDatasetTableMapper;
|
||||
import io.dataease.dataset.dto.DatasourceSchemaDTO;
|
||||
import io.dataease.dataset.utils.DatasetTableTypeConstants;
|
||||
import io.dataease.dataset.utils.SqlUtils;
|
||||
@ -24,6 +22,7 @@ import io.dataease.engine.constant.ExtFieldConstant;
|
||||
import io.dataease.engine.constant.SQLConstants;
|
||||
import io.dataease.exception.DEException;
|
||||
import io.dataease.i18n.Translator;
|
||||
import io.dataease.system.manage.CorePermissionManage;
|
||||
import io.dataease.utils.BeanUtils;
|
||||
import io.dataease.utils.JsonUtil;
|
||||
import jakarta.annotation.Resource;
|
||||
@ -31,7 +30,6 @@ import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
@ -44,16 +42,14 @@ import java.util.stream.Collectors;
|
||||
*/
|
||||
@Component
|
||||
public class DatasetSQLManage {
|
||||
@Resource
|
||||
private CoreDatasetTableMapper coreDatasetTableMapper;
|
||||
@Resource
|
||||
private DatasetTableFieldManage datasetTableFieldManage;
|
||||
|
||||
@Resource
|
||||
private CoreDatasourceMapper coreDatasourceMapper;
|
||||
@Resource
|
||||
private EngineServer engineServer;
|
||||
@Autowired(required = false)
|
||||
private InteractiveAuthApi interactiveAuthApi;
|
||||
|
||||
@Resource
|
||||
private CorePermissionManage corePermissionManage;
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(DatasetSQLManage.class);
|
||||
|
||||
@ -328,17 +324,15 @@ public class DatasetSQLManage {
|
||||
|
||||
private String putObj2Map(Map<Long, DatasourceSchemaDTO> dsMap, DatasetTableDTO ds) throws Exception {
|
||||
// 通过datasource id校验数据源权限
|
||||
if (interactiveAuthApi != null) {
|
||||
BusiPerCheckDTO dto = new BusiPerCheckDTO();
|
||||
dto.setId(ds.getDatasourceId());
|
||||
dto.setAuthEnum(AuthEnum.READ);
|
||||
try {
|
||||
interactiveAuthApi.checkAuth(dto);
|
||||
} catch (Exception e) {
|
||||
DEException.throwException(Translator.get("i18n_no_datasource_permission"));
|
||||
}
|
||||
BusiPerCheckDTO dto = new BusiPerCheckDTO();
|
||||
dto.setId(ds.getDatasourceId());
|
||||
dto.setAuthEnum(AuthEnum.READ);
|
||||
boolean checked = corePermissionManage.checkAuth(dto);
|
||||
if (!checked) {
|
||||
DEException.throwException(Translator.get("i18n_no_datasource_permission"));
|
||||
}
|
||||
|
||||
|
||||
String schemaAlias;
|
||||
if (StringUtils.equalsIgnoreCase(ds.getType(), DatasetTableType.DB) || StringUtils.equalsIgnoreCase(ds.getType(), DatasetTableType.SQL)) {
|
||||
CoreDatasource coreDatasource = coreDatasourceMapper.selectById(ds.getDatasourceId());
|
||||
|
@ -87,6 +87,13 @@ public class DataSourceManage {
|
||||
coreOptRecentManage.saveOpt(coreDatasource.getId(), OptConstants.OPT_RESOURCE_TYPE.DATASOURCE,OptConstants.OPT_TYPE.UPDATE);
|
||||
}
|
||||
|
||||
@XpackInteract(value = "datasourceResourceTree", before = false)
|
||||
public void innerEditStatus(CoreDatasource coreDatasource) {
|
||||
UpdateWrapper<CoreDatasource> updateWrapper = new UpdateWrapper<>();
|
||||
updateWrapper.eq("id", coreDatasource.getId());
|
||||
coreDatasourceMapper.update(coreDatasource, updateWrapper);
|
||||
}
|
||||
|
||||
@XpackInteract(value = "datasourceResourceTree", before = false)
|
||||
public void move(DatasourceDTO dataSourceDTO) {
|
||||
Long id = dataSourceDTO.getId();
|
||||
|
@ -53,8 +53,8 @@ public class CalciteProvider {
|
||||
private EngineServer engineServer;
|
||||
protected ExtendedJdbcClassLoader extendedJdbcClassLoader;
|
||||
private Map<Long, ExtendedJdbcClassLoader> customJdbcClassLoaders = new HashMap<>();
|
||||
private final String FILE_PATH = "/opt/dataease/drivers";
|
||||
private final String CUSTOM_PATH = "/opt/dataease/custom-drivers/";
|
||||
private final String FILE_PATH = "/opt/dataease2.0/drivers";
|
||||
private final String CUSTOM_PATH = "/opt/dataease2.0/custom-drivers/";
|
||||
private static String split = "DE";
|
||||
|
||||
@Resource
|
||||
|
@ -35,7 +35,7 @@ import java.util.stream.Collectors;
|
||||
|
||||
public class ExcelUtils {
|
||||
public static final String UFEFF = "\uFEFF";
|
||||
private static String path = "/opt/dataease/data/excel/";
|
||||
private static String path = "/opt/dataease2.0/data/excel/";
|
||||
private static ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
private static TypeReference<List<TableField>> TableFieldListTypeReference = new TypeReference<List<TableField>>() {
|
||||
|
@ -31,7 +31,7 @@ import java.util.*;
|
||||
@RequestMapping("/datasourceDriver")
|
||||
public class DatasourceDriverServer implements DatasourceDriverApi {
|
||||
|
||||
private final static String DRIVER_PATH = "/opt/dataease/custom-drivers/";
|
||||
private final static String DRIVER_PATH = "/opt/dataease2.0/custom-drivers/";
|
||||
|
||||
@Resource
|
||||
private CoreDriverMapper coreDriverMapper;
|
||||
|
@ -12,10 +12,6 @@ import io.dataease.api.dataset.dto.DatasetTableDTO;
|
||||
import io.dataease.api.dataset.dto.PreviewSqlDTO;
|
||||
import io.dataease.api.ds.DatasourceApi;
|
||||
import io.dataease.api.ds.vo.*;
|
||||
import io.dataease.api.permissions.auth.api.InteractiveAuthApi;
|
||||
import io.dataease.api.permissions.auth.dto.BusiResourceEditor;
|
||||
import io.dataease.api.permissions.user.api.UserApi;
|
||||
import io.dataease.api.permissions.user.vo.UserFormVO;
|
||||
import io.dataease.commons.constants.TaskStatus;
|
||||
import io.dataease.commons.utils.CommonThreadPool;
|
||||
import io.dataease.constant.DataSourceType;
|
||||
@ -34,18 +30,17 @@ import io.dataease.datasource.provider.ApiUtils;
|
||||
import io.dataease.datasource.provider.CalciteProvider;
|
||||
import io.dataease.datasource.provider.ExcelUtils;
|
||||
import io.dataease.datasource.request.DatasourceRequest;
|
||||
import io.dataease.datasource.type.Pg;
|
||||
import io.dataease.engine.constant.SQLConstants;
|
||||
import io.dataease.exception.DEException;
|
||||
import io.dataease.i18n.Translator;
|
||||
import io.dataease.license.config.XpackInteract;
|
||||
import io.dataease.model.BusiNodeRequest;
|
||||
import io.dataease.model.BusiNodeVO;
|
||||
import io.dataease.system.manage.CoreUserManage;
|
||||
import io.dataease.utils.*;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
@ -89,10 +84,10 @@ public class DatasourceServer implements DatasourceApi {
|
||||
private CoreDsFinishPageMapper coreDsFinishPageMapper;
|
||||
@Resource
|
||||
private DatasetDataManage datasetDataManage;
|
||||
@Autowired(required = false)
|
||||
private UserApi userApi;
|
||||
@Autowired(required = false)
|
||||
private InteractiveAuthApi interactiveAuthApi;
|
||||
|
||||
|
||||
@Resource
|
||||
private CoreUserManage coreUserManage;
|
||||
|
||||
@Override
|
||||
public List<DatasourceDTO> query(String keyWord) {
|
||||
@ -311,16 +306,16 @@ public class DatasourceServer implements DatasourceApi {
|
||||
|
||||
private static void checkParams(String configurationStr) {
|
||||
DatasourceConfiguration configuration = JsonUtil.parseObject(configurationStr, DatasourceConfiguration.class);
|
||||
if(configuration.getInitialPoolSize() < configuration.getMinPoolSize()){
|
||||
if (configuration.getInitialPoolSize() < configuration.getMinPoolSize()) {
|
||||
DEException.throwException("初始连接数不能小于最小连接数!");
|
||||
}
|
||||
if(configuration.getInitialPoolSize() > configuration.getMaxPoolSize()){
|
||||
if (configuration.getInitialPoolSize() > configuration.getMaxPoolSize()) {
|
||||
DEException.throwException("初始连接数不能大于最大连接数!");
|
||||
}
|
||||
if(configuration.getMaxPoolSize() < configuration.getMinPoolSize()){
|
||||
if (configuration.getMaxPoolSize() < configuration.getMinPoolSize()) {
|
||||
DEException.throwException("最大连接数不能小于最小连接数!");
|
||||
}
|
||||
if(configuration.getQueryTimeout() < 0){
|
||||
if (configuration.getQueryTimeout() < 0) {
|
||||
DEException.throwException("查询超时不能小于0!");
|
||||
}
|
||||
}
|
||||
@ -540,12 +535,8 @@ public class DatasourceServer implements DatasourceApi {
|
||||
}
|
||||
datasourceDTO.setConfiguration(new String(Base64.getEncoder().encode(datasourceDTO.getConfiguration().getBytes())));
|
||||
|
||||
if (userApi != null) {
|
||||
UserFormVO userFormVO = userApi.queryById(Long.valueOf(datasourceDTO.getCreateBy()));
|
||||
if (userFormVO != null) {
|
||||
datasourceDTO.setCreator(userFormVO.getName());
|
||||
}
|
||||
}
|
||||
datasourceDTO.setCreator(coreUserManage.getUserName(Long.valueOf(datasourceDTO.getCreateBy())));
|
||||
|
||||
return datasourceDTO;
|
||||
}
|
||||
|
||||
@ -622,14 +613,12 @@ public class DatasourceServer implements DatasourceApi {
|
||||
record.setStatus(coreDatasource.getStatus());
|
||||
QueryWrapper<CoreDatasource> wrapper = new QueryWrapper<>();
|
||||
wrapper.eq("id", coreDatasource.getId());
|
||||
datasourceMapper.update(record, wrapper);
|
||||
if (interactiveAuthApi != null) {
|
||||
BusiResourceEditor editor = new BusiResourceEditor();
|
||||
editor.setId((long) coreDatasource.getId());
|
||||
editor.setName(coreDatasource.getName());
|
||||
editor.setExtraFlag(getExtraFlag(coreDatasource.getType(), coreDatasource.getStatus()));
|
||||
interactiveAuthApi.editResource(editor);
|
||||
CoreDatasource originData = datasourceMapper.selectById(coreDatasource.getId());
|
||||
String originStatus = originData.getStatus();
|
||||
if (StringUtils.equals(coreDatasource.getStatus(), originStatus)) {
|
||||
return datasourceDTO;
|
||||
}
|
||||
dataSourceManage.innerEditStatus(coreDatasource);
|
||||
return datasourceDTO;
|
||||
}
|
||||
|
||||
@ -882,7 +871,7 @@ public class DatasourceServer implements DatasourceApi {
|
||||
List<DatasetTableDTO> datasetTableDTOS = ApiUtils.getTables(datasourceRequest);
|
||||
for (int i = 0; i < pager.getRecords().size(); i++) {
|
||||
for (int i1 = 0; i1 < datasetTableDTOS.size(); i1++) {
|
||||
if(pager.getRecords().get(i).getTableName().equalsIgnoreCase(datasetTableDTOS.get(i1).getTableName())){
|
||||
if (pager.getRecords().get(i).getTableName().equalsIgnoreCase(datasetTableDTOS.get(i1).getTableName())) {
|
||||
pager.getRecords().get(i).setName(datasetTableDTOS.get(i1).getName());
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,14 @@
|
||||
package io.dataease.system.manage;
|
||||
|
||||
import io.dataease.api.permissions.auth.dto.BusiPerCheckDTO;
|
||||
import io.dataease.license.config.XpackInteract;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class CorePermissionManage {
|
||||
|
||||
@XpackInteract(value = "corePermissionManage", replace = true)
|
||||
public boolean checkAuth(BusiPerCheckDTO dto) {
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package io.dataease.system.manage;
|
||||
|
||||
import io.dataease.license.config.XpackInteract;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class CoreUserManage {
|
||||
|
||||
|
||||
@XpackInteract(value = "coreUserManage", replace = true)
|
||||
public String getUserName(Long uid) {
|
||||
return "管理员";
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
spring:
|
||||
datasource:
|
||||
url: jdbc:mysql://127.0.0.1:3306/de_standalone?autoReconnect=false&useUnicode=true&characterEncoding=UTF-8&characterSetResults=UTF-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true
|
||||
url: jdbc:mysql://39.98.78.97:3306/dataease?autoReconnect=false&useUnicode=true&characterEncoding=UTF-8&characterSetResults=UTF-8&zeroDateTimeBehavior=convertToNull&useSSL=false
|
||||
username: root
|
||||
password: Password123@mysql
|
||||
messages:
|
||||
|
42
core/core-frontend/src/api/template.ts
Normal file
42
core/core-frontend/src/api/template.ts
Normal file
@ -0,0 +1,42 @@
|
||||
import request from '@/config/axios'
|
||||
|
||||
export function save(data) {
|
||||
return request.post({
|
||||
url: '/template/save',
|
||||
data: data,
|
||||
loading: true
|
||||
})
|
||||
}
|
||||
export function templateDelete(id) {
|
||||
return request.post({
|
||||
url: '/template/delete/' + id
|
||||
})
|
||||
}
|
||||
|
||||
export function showTemplateList(data) {
|
||||
return request.post({
|
||||
url: '/template/templateList',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function findOne(id) {
|
||||
return request.get({
|
||||
url: '/template/findOne/' + id
|
||||
})
|
||||
}
|
||||
|
||||
export function find(data) {
|
||||
return request.post({
|
||||
url: '/template/find',
|
||||
data: data,
|
||||
loading: true
|
||||
})
|
||||
}
|
||||
|
||||
export function nameCheck(data) {
|
||||
return request.post({
|
||||
url: '/template/nameCheck',
|
||||
data: data
|
||||
})
|
||||
}
|
14
core/core-frontend/src/api/templateMarket/index.js
Normal file
14
core/core-frontend/src/api/templateMarket/index.js
Normal file
@ -0,0 +1,14 @@
|
||||
import request from '@/config/axios'
|
||||
|
||||
export function searchMarket(data) {
|
||||
return request.post({
|
||||
url: '/template/market/search',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function getCategories() {
|
||||
return request.post({
|
||||
url: '/template/market/categories'
|
||||
})
|
||||
}
|
@ -287,7 +287,7 @@ const showEditPosition = computed(() => {
|
||||
if (showPosition.value === 'canvas') {
|
||||
const baseLeft = element.value.x - 1
|
||||
const baseRight = pcMatrixCount.value.x - (element.value.x + element.value.sizeX - 1)
|
||||
if (baseLeft === 0 && baseRight === 0) {
|
||||
if ((baseLeft === 0 && baseRight === 0) || baseRight < 0) {
|
||||
return 'bar-main-right-inner'
|
||||
} else if (baseRight === 0) {
|
||||
return 'bar-main-left-outer'
|
||||
|
@ -264,7 +264,7 @@ export default {
|
||||
data_source_table: '数据源表',
|
||||
auth_method: '认证方式',
|
||||
passwd: '用户名密码',
|
||||
kerbers_info: '请确保 krb5.Conf、Keytab Key,已经添加到路径:/opt/dataease/conf',
|
||||
kerbers_info: '请确保 krb5.Conf、Keytab Key,已经添加到路径:/opt/dataease2.0/conf',
|
||||
client_principal: 'Client Principal',
|
||||
keytab_Key_path: 'Keytab Key Path',
|
||||
please_select_left: '请从左侧选择',
|
||||
@ -1430,8 +1430,9 @@ export default {
|
||||
auth_num: '授权数量',
|
||||
version: '版本',
|
||||
version_num: '版本号',
|
||||
standard: '标准版',
|
||||
standard: '社区版',
|
||||
enterprise: '企业版',
|
||||
Embedded: '嵌入式版',
|
||||
support: '获取技术支持',
|
||||
update_success: '更新成功',
|
||||
serial_no: '序列号',
|
||||
@ -1629,7 +1630,7 @@ export default {
|
||||
weeks_4: '周四',
|
||||
weeks_5: '周五',
|
||||
weeks_6: '周六',
|
||||
system_parameter_setting: '系统参数设置',
|
||||
system_parameter_setting: '系统参数',
|
||||
connection_successful: '连接成功',
|
||||
connection_failed: '连接失败',
|
||||
save_failed: '保存失败',
|
||||
|
@ -150,7 +150,13 @@ const update = (licKey: string) => {
|
||||
<div class="item">
|
||||
<div class="label">{{ $t('about.version') }}</div>
|
||||
<div class="value">
|
||||
{{ license.edition === 'Standard' ? $t('about.standard') : $t('about.enterprise') }}
|
||||
{{
|
||||
!license?.edition
|
||||
? $t('about.standard')
|
||||
: license.edition === 'Embedded'
|
||||
? $t('about.Embedded')
|
||||
: $t('about.enterprise')
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
|
@ -175,14 +175,16 @@ const addItemBox = component => {
|
||||
}
|
||||
|
||||
const moveOutFromTab = component => {
|
||||
component.canvasId = canvasId.value
|
||||
dvMainStore.addComponent({
|
||||
component,
|
||||
index: undefined,
|
||||
isFromGroup: true,
|
||||
componentData: componentData.value
|
||||
})
|
||||
addItemBox(component)
|
||||
setTimeout(() => {
|
||||
component.canvasId = canvasId.value
|
||||
dvMainStore.addComponent({
|
||||
component,
|
||||
index: undefined,
|
||||
isFromGroup: true,
|
||||
componentData: componentData.value
|
||||
})
|
||||
addItemBox(component)
|
||||
}, 500)
|
||||
}
|
||||
|
||||
// 全局监听按键事件
|
||||
|
@ -173,33 +173,10 @@ const dsClick = (data: Tree) => {
|
||||
}
|
||||
//选中赋值
|
||||
_modelValue.value = data.id
|
||||
getFields(data.id, props.viewId)
|
||||
//关闭弹窗
|
||||
datasetSelectorPopover.value?.hide()
|
||||
}
|
||||
}
|
||||
const getFields = (id, chartId) => {
|
||||
if (id && chartId) {
|
||||
getFieldByDQ(id, chartId)
|
||||
.then(res => {
|
||||
state.value.dimension = (res.dimensionList as unknown as Field[]) || []
|
||||
state.value.quota = (res.quotaList as unknown as Field[]) || []
|
||||
state.value.dimensionData = JSON.parse(JSON.stringify(state.value.dimension))
|
||||
state.value.quotaData = JSON.parse(JSON.stringify(state.value.quota))
|
||||
})
|
||||
.catch(() => {
|
||||
state.value.dimension = []
|
||||
state.value.quota = []
|
||||
state.value.dimensionData = []
|
||||
state.value.quotaData = []
|
||||
})
|
||||
} else {
|
||||
state.value.dimension = []
|
||||
state.value.quota = []
|
||||
state.value.dimensionData = []
|
||||
state.value.quotaData = []
|
||||
}
|
||||
}
|
||||
const _popoverShow = ref(false)
|
||||
function onPopoverShow() {
|
||||
_popoverShow.value = true
|
||||
|
@ -69,7 +69,7 @@ const initSeriesTooltip = () => {
|
||||
...next,
|
||||
seriesId: next.seriesId ?? next.id,
|
||||
show: index <= quotaAxis.value.length - 1,
|
||||
summary: 'sum'
|
||||
summary: COUNT_DE_TYPE.includes(next.deType) ? 'count' : 'sum'
|
||||
} as SeriesFormatter
|
||||
if (seriesAxisMap[tmp.seriesId]) {
|
||||
tmp = {
|
||||
@ -136,6 +136,18 @@ const AGGREGATION_TYPE = [
|
||||
{ name: t('chart.count'), value: 'count' },
|
||||
{ name: t('chart.count_distinct'), value: 'count_distinct' }
|
||||
]
|
||||
const COUNT_AGGREGATION_TYPE = [
|
||||
{ name: t('chart.count'), value: 'count' },
|
||||
{ name: t('chart.count_distinct'), value: 'count_distinct' }
|
||||
]
|
||||
const COUNT_DE_TYPE = [0, 1, 5]
|
||||
|
||||
const aggregationList = computed(() => {
|
||||
if (COUNT_DE_TYPE.includes(curSeriesFormatter.value?.deType)) {
|
||||
return COUNT_AGGREGATION_TYPE
|
||||
}
|
||||
return AGGREGATION_TYPE
|
||||
})
|
||||
watch(
|
||||
[() => props.chart.customAttr.tooltip, () => props.chart.customAttr.tooltip.show],
|
||||
() => {
|
||||
@ -188,10 +200,8 @@ const init = () => {
|
||||
formatterSelector.value?.blur()
|
||||
// 新增视图
|
||||
const formatter = state.tooltipForm.seriesTooltipFormatter
|
||||
if (!quotaAxis.value?.length) {
|
||||
if (!formatter.length) {
|
||||
quotaData.value?.forEach(i => formatter.push({ ...i, seriesId: i.id, show: false }))
|
||||
}
|
||||
if (!formatter.length) {
|
||||
quotaData.value?.forEach(i => formatter.push({ ...i, seriesId: i.id, show: false }))
|
||||
curSeriesFormatter.value = {}
|
||||
return
|
||||
}
|
||||
@ -209,7 +219,13 @@ const init = () => {
|
||||
}
|
||||
}
|
||||
|
||||
const showProperty = prop => props.propertyInner?.includes(prop)
|
||||
const showProperty = prop => {
|
||||
const instance = chartViewManager.getChartView(props.chart.render, props.chart.type)
|
||||
if (instance) {
|
||||
return instance.propertyInner['tooltip-selector'].includes(prop)
|
||||
}
|
||||
return props.propertyInner?.includes(prop)
|
||||
}
|
||||
const updateSeriesTooltipFormatter = (form: AxisEditForm) => {
|
||||
const { axisType, editType } = form
|
||||
if (
|
||||
@ -575,7 +591,7 @@ onMounted(() => {
|
||||
@change="changeTooltipAttr('seriesTooltipFormatter', true)"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in AGGREGATION_TYPE"
|
||||
v-for="item in aggregationList"
|
||||
:label="item.name"
|
||||
:value="item.value"
|
||||
:key="item.value"
|
||||
|
@ -49,6 +49,7 @@ import chartViewManager from '@/views/chart/components/js/panel'
|
||||
import DatasetSelect from '@/views/chart/components/editor/dataset-select/DatasetSelect.vue'
|
||||
import { useDraggable } from '@vueuse/core'
|
||||
import { set, concat, keys } from 'lodash-es'
|
||||
import { Field, getFieldByDQ } from '@/api/chart'
|
||||
|
||||
const snapshotStore = snapshotStoreWithOut()
|
||||
const dvMainStore = dvMainStoreWithOut()
|
||||
@ -146,6 +147,7 @@ const state = reactive({
|
||||
watch(
|
||||
[() => view.value['tableId']],
|
||||
() => {
|
||||
getFields(props.view.tableId, props.view.id)
|
||||
const nodeId = view.value['tableId']
|
||||
if (!!nodeId) {
|
||||
cacheId = nodeId as unknown as string
|
||||
@ -157,7 +159,28 @@ watch(
|
||||
},
|
||||
{ deep: true }
|
||||
)
|
||||
|
||||
const getFields = (id, chartId) => {
|
||||
if (id && chartId) {
|
||||
getFieldByDQ(id, chartId)
|
||||
.then(res => {
|
||||
state.dimension = (res.dimensionList as unknown as Field[]) || []
|
||||
state.quota = (res.quotaList as unknown as Field[]) || []
|
||||
state.dimensionData = JSON.parse(JSON.stringify(state.dimension))
|
||||
state.quotaData = JSON.parse(JSON.stringify(state.quota))
|
||||
})
|
||||
.catch(() => {
|
||||
state.dimension = []
|
||||
state.quota = []
|
||||
state.dimensionData = []
|
||||
state.quotaData = []
|
||||
})
|
||||
} else {
|
||||
state.dimension = []
|
||||
state.quota = []
|
||||
state.dimensionData = []
|
||||
state.quotaData = []
|
||||
}
|
||||
}
|
||||
watch(
|
||||
[() => state.searchField],
|
||||
newVal => {
|
||||
|
@ -116,6 +116,7 @@ export class Bar extends G2PlotChartView<ColumnOptions, Column> {
|
||||
pre[next.id] = next
|
||||
return pre
|
||||
}, {})
|
||||
// 默认是灰色
|
||||
tmpOptions.label.style.fill = DEFAULT_LABEL.color
|
||||
const label = {
|
||||
fields: [],
|
||||
@ -242,6 +243,7 @@ export class StackBar extends Bar {
|
||||
return baseOptions
|
||||
}
|
||||
const { label: labelAttr } = parseJson(chart.customAttr)
|
||||
baseOptions.label.style.fill = labelAttr.color
|
||||
const label = {
|
||||
...baseOptions.label,
|
||||
formatter: function (param: Datum) {
|
||||
|
@ -164,11 +164,12 @@ export class HorizontalBar extends G2PlotChartView<BarOptions, Bar> {
|
||||
}
|
||||
|
||||
setupDefaultOptions(chart: ChartObj): ChartObj {
|
||||
const { customAttr } = chart
|
||||
const { customAttr, senior } = chart
|
||||
const { label } = customAttr
|
||||
if (!['left', 'middle', 'right'].includes(label.position)) {
|
||||
label.position = 'middle'
|
||||
}
|
||||
senior.functionCfg.emptyDataStrategy = 'ignoreData'
|
||||
return chart
|
||||
}
|
||||
|
||||
@ -185,6 +186,7 @@ export class HorizontalBar extends G2PlotChartView<BarOptions, Bar> {
|
||||
pre[next.id] = next
|
||||
return pre
|
||||
}, {})
|
||||
// 默认灰色
|
||||
tmpOptions.label.style.fill = DEFAULT_LABEL.color
|
||||
const label = {
|
||||
fields: [],
|
||||
@ -272,6 +274,7 @@ export class HorizontalStackBar extends HorizontalBar {
|
||||
return baseOptions
|
||||
}
|
||||
const { label: labelAttr } = parseJson(chart.customAttr)
|
||||
baseOptions.label.style.fill = labelAttr.color
|
||||
const label = {
|
||||
...baseOptions.label,
|
||||
formatter: function (param: Datum) {
|
||||
|
@ -78,7 +78,7 @@ export class WordCloud extends G2PlotChartView<WordCloudOptions, G2WordCloud> {
|
||||
const options = this.setupOptions(chart, initOptions)
|
||||
const newChart = new G2WordCloud(container, options)
|
||||
newChart.on('point:click', param => {
|
||||
action({ data: { data: param.data.data.datum } })
|
||||
action({ x: param.x, y: param.y, data: { data: param.data.data.datum } })
|
||||
})
|
||||
return newChart
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
<template>
|
||||
<div class="info-card">
|
||||
<div class="info-title">{{ t('visualization.create_by') }}</div>
|
||||
<div class="info-content">{{ dvInfo.creatorName || 'N/A' }}</div>
|
||||
<div v-if="dvInfo.creatorName" class="info-title">{{ t('visualization.create_by') }}</div>
|
||||
<div v-if="dvInfo.creatorName" class="info-content">{{ dvInfo.creatorName }}</div>
|
||||
<div class="info-title">{{ t('visualization.create_time') }}</div>
|
||||
<div class="info-content">{{ timestampFormatDate(dvInfo.createTime) }}</div>
|
||||
<div class="info-title">{{ t('visualization.update_by') }}</div>
|
||||
<div class="info-content">{{ dvInfo.updateName || 'N/A' }}</div>
|
||||
<div v-if="dvInfo.updateName" class="info-title">{{ t('visualization.update_by') }}</div>
|
||||
<div v-if="dvInfo.updateName" class="info-content">{{ dvInfo.updateName }}</div>
|
||||
<div class="info-title">{{ t('visualization.update_time') }}</div>
|
||||
<div v-if="dvInfo.updateTime" class="info-content">
|
||||
{{ timestampFormatDate(dvInfo.updateTime) }}
|
||||
|
@ -93,6 +93,7 @@ watch(
|
||||
jsname="L2NvbXBvbmVudC9zaGFyZS9TaGFyZVZpc3VhbEhlYWQ="
|
||||
:resource-id="dvInfo.id"
|
||||
:weight="dvInfo.weight"
|
||||
:resource-type="dvInfo.type"
|
||||
/>
|
||||
<el-button v-if="dvInfo.weight > 6" type="primary" @click="dvEdit()">
|
||||
<template #icon>
|
||||
|
230
core/core-frontend/src/views/system/common/InfoTemplate.vue
Normal file
230
core/core-frontend/src/views/system/common/InfoTemplate.vue
Normal file
@ -0,0 +1,230 @@
|
||||
<template>
|
||||
<div class="info-template-container">
|
||||
<div class="info-template-header">
|
||||
<div class="info-template-title">
|
||||
<span>基础设置</span>
|
||||
</div>
|
||||
<div>
|
||||
<el-button type="primary" @click="edit">{{ t('commons.edit') }}</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<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>
|
||||
<el-tooltip
|
||||
v-if="tooltipItem[item.pkey]"
|
||||
effect="dark"
|
||||
:content="tooltipItem[item.pkey]"
|
||||
placement="top"
|
||||
>
|
||||
<el-icon class="info-tips"><Icon name="dv-info"></Icon></el-icon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<div class="info-item-content">
|
||||
<div class="info-item-pwd" v-if="item.type === 'pwd'">
|
||||
<span>{{ pwdItem[item.pkey]['hidden'] ? '********' : item.pval }}</span>
|
||||
<el-tooltip effect="dark" content="新页面预览" placement="top">
|
||||
<el-icon
|
||||
class="hover-icon hover-icon-in-table switch-pwd-icon"
|
||||
@click="switchPwd(item.pkey)"
|
||||
>
|
||||
<Icon :name="pwdItem[item.pkey]['hidden'] ? 'eye' : 'eye-open'"></Icon>
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<span v-else>{{ item.pval }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, defineProps, PropType } from 'vue'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { SettingRecord, ToolTipRecord } from './SettingTemplate'
|
||||
const { t } = useI18n()
|
||||
const props = defineProps({
|
||||
settingKey: {
|
||||
type: String,
|
||||
default: 'basic'
|
||||
},
|
||||
labelTooltips: {
|
||||
type: Array as PropType<ToolTipRecord[]>,
|
||||
default: () => []
|
||||
}
|
||||
})
|
||||
|
||||
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.settingKey === 'basic') {
|
||||
loadBasic()
|
||||
}
|
||||
if (props.settingKey === 'email') {
|
||||
loadEmail()
|
||||
}
|
||||
}
|
||||
const pwdItem = ref({})
|
||||
|
||||
const formatPwd = () => {
|
||||
settingList.value.forEach(setting => {
|
||||
if (setting.type === 'pwd') {
|
||||
pwdItem.value[setting.pkey] = { hidden: true }
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const tooltipItem = ref({})
|
||||
const formatLabel = () => {
|
||||
props.labelTooltips?.length &&
|
||||
props.labelTooltips.forEach(tooltip => {
|
||||
tooltipItem.value[tooltip.key] = tooltip.val
|
||||
})
|
||||
}
|
||||
|
||||
const switchPwd = (pkey: string) => {
|
||||
pwdItem.value[pkey]['hidden'] = !pwdItem.value[pkey]['hidden']
|
||||
}
|
||||
|
||||
const emits = defineEmits(['edit'])
|
||||
const edit = () => {
|
||||
emits('edit')
|
||||
}
|
||||
init()
|
||||
formatPwd()
|
||||
formatLabel()
|
||||
</script>
|
||||
|
||||
<style lang="less" scope>
|
||||
.info-template-container {
|
||||
padding: 24px;
|
||||
.info-template-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
.info-template-title {
|
||||
height: 24px;
|
||||
line-height: 23px;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: #1f2329;
|
||||
}
|
||||
}
|
||||
.info-template-content {
|
||||
width: 100%;
|
||||
margin: 8px 0;
|
||||
.info-content-item {
|
||||
width: 50%;
|
||||
height: 48px;
|
||||
float: left;
|
||||
margin-bottom: 16px;
|
||||
.info-item-label {
|
||||
height: 22px;
|
||||
line-height: 22px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
span {
|
||||
font-size: 14px;
|
||||
color: #646a73;
|
||||
font-weight: 400;
|
||||
}
|
||||
i {
|
||||
margin-left: 2px;
|
||||
}
|
||||
}
|
||||
.info-item-content {
|
||||
line-height: 22px;
|
||||
height: 22px;
|
||||
span {
|
||||
font-size: 14px;
|
||||
color: #1f2329;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.info-item-pwd {
|
||||
height: 22px;
|
||||
line-height: 22px;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
i {
|
||||
margin-left: 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -0,0 +1,11 @@
|
||||
export interface SettingRecord {
|
||||
pkey: string
|
||||
pval: string
|
||||
type: string
|
||||
sort: number
|
||||
}
|
||||
|
||||
export interface ToolTipRecord {
|
||||
key: string
|
||||
val: string
|
||||
}
|
@ -0,0 +1,171 @@
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive } from 'vue'
|
||||
import { ElMessage, ElLoading } from 'element-plus-secondary'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import type { FormInstance, FormRules } from 'element-plus-secondary'
|
||||
|
||||
const { t } = useI18n()
|
||||
const dialogVisible = ref(false)
|
||||
const loadingInstance = ref(null)
|
||||
const createUserForm = ref<FormInstance>()
|
||||
const state = reactive({
|
||||
roleList: [],
|
||||
form: reactive<UserForm>({
|
||||
id: null,
|
||||
account: null,
|
||||
name: null,
|
||||
email: null,
|
||||
enable: true,
|
||||
phone: null,
|
||||
phonePrefix: '+86',
|
||||
roleIds: []
|
||||
})
|
||||
})
|
||||
|
||||
const rule = reactive<FormRules>({})
|
||||
|
||||
const edit = () => {
|
||||
dialogVisible.value = true
|
||||
// queryForm()
|
||||
}
|
||||
/* const queryForm = () => {
|
||||
showLoading()
|
||||
personInfoApi().then(res => {
|
||||
state.form = reactive<UserForm>(res.data)
|
||||
closeLoading()
|
||||
})
|
||||
} */
|
||||
const emits = defineEmits(['saved'])
|
||||
const submitForm = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
await formEl.validate((valid, fields) => {
|
||||
if (valid) {
|
||||
const param = { ...state.form }
|
||||
const method = null
|
||||
showLoading()
|
||||
method(param)
|
||||
.then(res => {
|
||||
if (!res.msg) {
|
||||
ElMessage.success(t('common.save_success'))
|
||||
|
||||
emits('saved')
|
||||
reset()
|
||||
}
|
||||
closeLoading()
|
||||
})
|
||||
.catch(() => {
|
||||
closeLoading()
|
||||
})
|
||||
} else {
|
||||
console.log('error submit!', fields)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const resetForm = (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
formEl.resetFields()
|
||||
dialogVisible.value = false
|
||||
}
|
||||
|
||||
const reset = () => {
|
||||
resetForm(createUserForm.value)
|
||||
}
|
||||
|
||||
const showLoading = () => {
|
||||
loadingInstance.value = ElLoading.service({ target: '.basic-info-drawer' })
|
||||
}
|
||||
const closeLoading = () => {
|
||||
loadingInstance.value?.close()
|
||||
}
|
||||
defineExpose({
|
||||
edit
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-drawer
|
||||
title="基础设置"
|
||||
v-model="dialogVisible"
|
||||
custom-class="basic-info-drawer"
|
||||
size="600px"
|
||||
direction="rtl"
|
||||
>
|
||||
<el-form
|
||||
ref="createUserForm"
|
||||
require-asterisk-position="right"
|
||||
:model="state.form"
|
||||
:rules="rule"
|
||||
label-width="80px"
|
||||
label-position="top"
|
||||
>
|
||||
<el-form-item label="请求超时时间" prop="name">
|
||||
<el-input
|
||||
v-model="state.form.name"
|
||||
:placeholder="t('common.please_input') + t('user.name')"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="数据源检测时间间隔" prop="account">
|
||||
<el-input
|
||||
v-model="state.form.account"
|
||||
:placeholder="t('common.please_input') + t('common.account')"
|
||||
disabled
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="resetForm(createUserForm)">{{ t('common.cancel') }}</el-button>
|
||||
<el-button type="primary" @click="submitForm(createUserForm)">
|
||||
{{ t('commons.save') }}
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</template>
|
||||
|
||||
<style lang="less">
|
||||
.basic-info-drawer {
|
||||
.editer-form-title {
|
||||
width: 100%;
|
||||
border-radius: 4px;
|
||||
background: #e1eaff;
|
||||
margin: -8px 0 16px 0;
|
||||
height: 40px;
|
||||
padding-left: 16px;
|
||||
|
||||
i {
|
||||
color: #3370ff;
|
||||
font-size: 14.666666030883789px;
|
||||
}
|
||||
|
||||
.pwd {
|
||||
font-family: PingFang SC;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
line-height: 22px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.pwd {
|
||||
margin: 0 8px;
|
||||
color: #1f2329;
|
||||
}
|
||||
}
|
||||
.input-with-select {
|
||||
.ed-input-group__prepend {
|
||||
width: 72px;
|
||||
background-color: #fff;
|
||||
padding: 0 20px;
|
||||
color: #1f2329;
|
||||
text-align: center;
|
||||
font-family: PingFang SC;
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 22px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -0,0 +1,22 @@
|
||||
<template>
|
||||
<InfoTemplate :label-tooltips="tooltips" setting-key="basic" @edit="edit" />
|
||||
<basic-edit ref="editor" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue'
|
||||
import InfoTemplate from '../../common/InfoTemplate.vue'
|
||||
import BasicEdit from './BasicEdit.vue'
|
||||
|
||||
const editor = ref()
|
||||
const tooltips = [
|
||||
{
|
||||
key: '请求超时时间',
|
||||
val: '请求超时时间(单位:秒,注意:保存后刷新浏览器生效)'
|
||||
}
|
||||
]
|
||||
|
||||
const edit = () => {
|
||||
editor?.value.edit()
|
||||
}
|
||||
</script>
|
@ -0,0 +1,171 @@
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive } from 'vue'
|
||||
import { ElMessage, ElLoading } from 'element-plus-secondary'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import type { FormInstance, FormRules } from 'element-plus-secondary'
|
||||
|
||||
const { t } = useI18n()
|
||||
const dialogVisible = ref(false)
|
||||
const loadingInstance = ref(null)
|
||||
const createUserForm = ref<FormInstance>()
|
||||
const state = reactive({
|
||||
roleList: [],
|
||||
form: reactive<UserForm>({
|
||||
id: null,
|
||||
account: null,
|
||||
name: null,
|
||||
email: null,
|
||||
enable: true,
|
||||
phone: null,
|
||||
phonePrefix: '+86',
|
||||
roleIds: []
|
||||
})
|
||||
})
|
||||
|
||||
const rule = reactive<FormRules>({})
|
||||
|
||||
const edit = () => {
|
||||
dialogVisible.value = true
|
||||
// queryForm()
|
||||
}
|
||||
/* const queryForm = () => {
|
||||
showLoading()
|
||||
personInfoApi().then(res => {
|
||||
state.form = reactive<UserForm>(res.data)
|
||||
closeLoading()
|
||||
})
|
||||
} */
|
||||
const emits = defineEmits(['saved'])
|
||||
const submitForm = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
await formEl.validate((valid, fields) => {
|
||||
if (valid) {
|
||||
const param = { ...state.form }
|
||||
const method = null
|
||||
showLoading()
|
||||
method(param)
|
||||
.then(res => {
|
||||
if (!res.msg) {
|
||||
ElMessage.success(t('common.save_success'))
|
||||
|
||||
emits('saved')
|
||||
reset()
|
||||
}
|
||||
closeLoading()
|
||||
})
|
||||
.catch(() => {
|
||||
closeLoading()
|
||||
})
|
||||
} else {
|
||||
console.log('error submit!', fields)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const resetForm = (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
formEl.resetFields()
|
||||
dialogVisible.value = false
|
||||
}
|
||||
|
||||
const reset = () => {
|
||||
resetForm(createUserForm.value)
|
||||
}
|
||||
|
||||
const showLoading = () => {
|
||||
loadingInstance.value = ElLoading.service({ target: '.basic-info-drawer' })
|
||||
}
|
||||
const closeLoading = () => {
|
||||
loadingInstance.value?.close()
|
||||
}
|
||||
defineExpose({
|
||||
edit
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-drawer
|
||||
title="邮件设置"
|
||||
v-model="dialogVisible"
|
||||
custom-class="basic-info-drawer"
|
||||
size="600px"
|
||||
direction="rtl"
|
||||
>
|
||||
<el-form
|
||||
ref="createUserForm"
|
||||
require-asterisk-position="right"
|
||||
:model="state.form"
|
||||
:rules="rule"
|
||||
label-width="80px"
|
||||
label-position="top"
|
||||
>
|
||||
<el-form-item label="请求超时时间" prop="name">
|
||||
<el-input
|
||||
v-model="state.form.name"
|
||||
:placeholder="t('common.please_input') + t('user.name')"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="数据源检测时间间隔" prop="account">
|
||||
<el-input
|
||||
v-model="state.form.account"
|
||||
:placeholder="t('common.please_input') + t('common.account')"
|
||||
disabled
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="resetForm(createUserForm)">{{ t('common.cancel') }}</el-button>
|
||||
<el-button type="primary" @click="submitForm(createUserForm)">
|
||||
{{ t('commons.save') }}
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</template>
|
||||
|
||||
<style lang="less">
|
||||
.basic-info-drawer {
|
||||
.editer-form-title {
|
||||
width: 100%;
|
||||
border-radius: 4px;
|
||||
background: #e1eaff;
|
||||
margin: -8px 0 16px 0;
|
||||
height: 40px;
|
||||
padding-left: 16px;
|
||||
|
||||
i {
|
||||
color: #3370ff;
|
||||
font-size: 14.666666030883789px;
|
||||
}
|
||||
|
||||
.pwd {
|
||||
font-family: PingFang SC;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
line-height: 22px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.pwd {
|
||||
margin: 0 8px;
|
||||
color: #1f2329;
|
||||
}
|
||||
}
|
||||
.input-with-select {
|
||||
.ed-input-group__prepend {
|
||||
width: 72px;
|
||||
background-color: #fff;
|
||||
padding: 0 20px;
|
||||
color: #1f2329;
|
||||
text-align: center;
|
||||
font-family: PingFang SC;
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 22px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -0,0 +1,30 @@
|
||||
<template>
|
||||
<InfoTemplate :label-tooltips="tooltips" setting-key="email" @edit="edit" />
|
||||
<email-edit ref="editor" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue'
|
||||
import InfoTemplate from '../../common/InfoTemplate.vue'
|
||||
import EmailEdit from './EmailEdit.vue'
|
||||
const tooltips = [
|
||||
{
|
||||
key: '测试收件人',
|
||||
val: '测试收件人xxxx'
|
||||
},
|
||||
{
|
||||
key: 'SSL',
|
||||
val: 'SSLxxxx'
|
||||
},
|
||||
{
|
||||
key: 'TSL',
|
||||
val: 'TSLxxxx'
|
||||
}
|
||||
]
|
||||
|
||||
const editor = ref()
|
||||
|
||||
const edit = () => {
|
||||
editor?.value.edit()
|
||||
}
|
||||
</script>
|
@ -1,11 +1,13 @@
|
||||
<template>
|
||||
<p class="router-title">系统参数</p>
|
||||
<p class="router-title">{{ t('commons.system_parameter_setting') }}</p>
|
||||
<el-tabs v-model="activeName" @tab-click="handleClick">
|
||||
<el-tab-pane v-for="item in tabArray" :key="item.name" :label="item.label" :name="item.name" />
|
||||
</el-tabs>
|
||||
<div class="sys-setting-p">
|
||||
<div class="sys-setting-p" :class="{ 'setting-auto-h': activeName !== 'map' }">
|
||||
<div class="container-sys-param">
|
||||
<map-setting v-if="activeName === 'map'" />
|
||||
<basic-info v-if="activeName === 'basic'" />
|
||||
<email-info v-if="activeName === 'email'" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -14,15 +16,17 @@
|
||||
import { ref } from 'vue'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import MapSetting from './map/MapSetting.vue'
|
||||
import BasicInfo from './basic/BasicInfo.vue'
|
||||
import EmailInfo from './email/EmailInfo.vue'
|
||||
const { t } = useI18n()
|
||||
|
||||
const tabArray = [
|
||||
/* {label: '基础设置', name: 'basic'},
|
||||
{label: '邮件设置', name: 'email'}, */
|
||||
{ label: '基础设置', name: 'basic' },
|
||||
{ label: '邮件设置', name: 'email' },
|
||||
{ label: '地图设置', name: 'map' }
|
||||
/* {label: '引擎设置', name: 'engine'}, */
|
||||
]
|
||||
const activeName = ref('map')
|
||||
const activeName = ref('basic')
|
||||
const handleClick = (tab, event: Event) => {
|
||||
console.log(tab, event)
|
||||
}
|
||||
@ -44,6 +48,9 @@ const handleClick = (tab, event: Event) => {
|
||||
box-sizing: border-box;
|
||||
margin-top: 12px;
|
||||
}
|
||||
.setting-auto-h {
|
||||
height: auto !important;
|
||||
}
|
||||
|
||||
.container-sys-param {
|
||||
height: 100%;
|
||||
|
@ -0,0 +1,209 @@
|
||||
<template>
|
||||
<div class="template-import">
|
||||
<el-form
|
||||
ref="templateImportForm"
|
||||
class="de-form-item"
|
||||
:model="state.templateInfo"
|
||||
:rules="state.templateInfoRules"
|
||||
>
|
||||
<el-form-item :label="t('system_parameter_setting.template_name')" prop="name">
|
||||
<div class="flex-template">
|
||||
<el-input v-model="state.templateInfo.name" clearable size="small" />
|
||||
<el-button style="margin-left: 10px" class="el-icon-upload2" secondary @click="goFile">{{
|
||||
t('panel.upload_template')
|
||||
}}</el-button>
|
||||
<input
|
||||
id="input"
|
||||
ref="filesRef"
|
||||
type="file"
|
||||
accept=".DET"
|
||||
hidden
|
||||
@change="handleFileChange"
|
||||
/>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-row class="preview" :style="classBackground" />
|
||||
<el-row class="de-root-class">
|
||||
<deBtn secondary @click="cancel()">{{ t('commons.cancel') }}</deBtn>
|
||||
<deBtn type="primary" @click="saveTemplate()">{{ t('commons.confirm') }}</deBtn>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { save, nameCheck, find } from '@/api/template'
|
||||
import { computed, onMounted, reactive, ref } from 'vue'
|
||||
import { imgUrlTrans } from '@/utils/imgUtils'
|
||||
import { ElMessage } from 'element-plus-secondary'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
const emits = defineEmits(['closeEditTemplateDialog', 'refresh'])
|
||||
const { t } = useI18n()
|
||||
const filesRef = ref(null)
|
||||
const props = defineProps({
|
||||
pid: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
})
|
||||
|
||||
const state = reactive({
|
||||
nameList: [],
|
||||
importTemplateInfo: {
|
||||
snapshot: ''
|
||||
},
|
||||
templateInfoRules: {
|
||||
name: [
|
||||
{
|
||||
required: true,
|
||||
message: t('commons.input_content'),
|
||||
trigger: 'change'
|
||||
}
|
||||
]
|
||||
},
|
||||
recover: false,
|
||||
templateInfo: {
|
||||
level: '1',
|
||||
pid: props.pid,
|
||||
name: '',
|
||||
templateStyle: null,
|
||||
templateData: null,
|
||||
dynamicData: null,
|
||||
staticResource: null,
|
||||
snapshot: ''
|
||||
}
|
||||
})
|
||||
|
||||
const classBackground = computed(() => {
|
||||
if (state.importTemplateInfo.snapshot) {
|
||||
return {
|
||||
background: `url(${imgUrlTrans(state.importTemplateInfo.snapshot)}) no-repeat`
|
||||
}
|
||||
} else {
|
||||
return {}
|
||||
}
|
||||
})
|
||||
|
||||
const showCurrentTemplate = pid => {
|
||||
find({ pid }).then(response => {
|
||||
state.nameList = response.data
|
||||
})
|
||||
}
|
||||
const cancel = () => {
|
||||
emits('closeEditTemplateDialog')
|
||||
}
|
||||
|
||||
const saveTemplate = () => {
|
||||
if (!state.templateInfo.name) {
|
||||
ElMessage.warning(t('chart.name_can_not_empty'))
|
||||
return false
|
||||
}
|
||||
if (!state.templateInfo.templateData) {
|
||||
ElMessage.warning(t('chart.template_can_not_empty'))
|
||||
return false
|
||||
}
|
||||
const nameCheckRequest = {
|
||||
pid: state.templateInfo.pid,
|
||||
name: state.templateInfo.name,
|
||||
optType: 'insert'
|
||||
}
|
||||
nameCheck(nameCheckRequest).then(response => {
|
||||
if (response.data.indexOf('exist') > -1) {
|
||||
const options = {
|
||||
title: 'commons.prompt',
|
||||
content: 'system_parameter_setting.to_overwrite_them',
|
||||
type: 'primary',
|
||||
cb: () =>
|
||||
save(state.templateInfo).then(response => {
|
||||
ElMessage.success(t('system_parameter_setting.import_succeeded'))
|
||||
emits('refresh')
|
||||
emits('closeEditTemplateDialog')
|
||||
}),
|
||||
confirmButtonText: t('template.override')
|
||||
}
|
||||
handlerConfirm(options)
|
||||
} else {
|
||||
save(state.templateInfo).then(response => {
|
||||
ElMessage.success(t('system_parameter_setting.import_succeeded'))
|
||||
emits('refresh')
|
||||
emits('closeEditTemplateDialog')
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const handlerConfirm = option => {
|
||||
// do handlerConfirm
|
||||
}
|
||||
|
||||
const handleFileChange = e => {
|
||||
const file = e.target.files[0]
|
||||
const reader = new FileReader()
|
||||
reader.onload = res => {
|
||||
const result = res.target.result as string
|
||||
state.importTemplateInfo = JSON.parse(result)
|
||||
state.templateInfo.name = state.importTemplateInfo['name']
|
||||
state.templateInfo.templateStyle = state.importTemplateInfo['panelStyle']
|
||||
state.templateInfo.templateData = state.importTemplateInfo['panelData']
|
||||
state.templateInfo.snapshot = state.importTemplateInfo.snapshot
|
||||
state.templateInfo.dynamicData = state.importTemplateInfo['dynamicData']
|
||||
state.templateInfo.staticResource = state.importTemplateInfo['staticResource']
|
||||
state.templateInfo['nodeType'] = 'template'
|
||||
}
|
||||
reader.readAsText(file)
|
||||
}
|
||||
const goFile = () => {
|
||||
filesRef.value.click()
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
showCurrentTemplate(props.pid)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.my_table :deep(.el-table__row > td) {
|
||||
/* 去除表格线 */
|
||||
border: none;
|
||||
padding: 0 0;
|
||||
}
|
||||
.my_table :deep(.el-table th.is-leaf) {
|
||||
/* 去除上边框 */
|
||||
border: none;
|
||||
}
|
||||
.my_table :deep(.el-table::before) {
|
||||
/* 去除下边框 */
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.de-root-class {
|
||||
margin-top: 24px;
|
||||
text-align: right;
|
||||
}
|
||||
.preview {
|
||||
margin-top: -12px;
|
||||
border: 1px solid #e6e6e6;
|
||||
height: 300px !important;
|
||||
overflow: auto;
|
||||
background-size: 100% 100% !important;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.preview-show {
|
||||
border-left: 1px solid #e6e6e6;
|
||||
height: 300px;
|
||||
background-size: 100% 100% !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss">
|
||||
.flex-template {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
.el-input {
|
||||
margin-right: 2px;
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
</style>
|
140
core/core-frontend/src/views/template/component/TemplateItem.vue
Normal file
140
core/core-frontend/src/views/template/component/TemplateItem.vue
Normal file
@ -0,0 +1,140 @@
|
||||
<template>
|
||||
<div :style="classBackground" class="de-card-model">
|
||||
<div class="card-img-model" :style="classImg">
|
||||
<img :src="model.snapshot" alt="" />
|
||||
</div>
|
||||
<div class="card-info">
|
||||
<el-tooltip class="item" effect="dark" :content="model.name" placement="top">
|
||||
<span class="de-model-text">{{ model.name }}</span>
|
||||
</el-tooltip>
|
||||
<el-dropdown size="medium" trigger="click" @command="handleCommand">
|
||||
<i class="el-icon-more" />
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu class="de-card-dropdown">
|
||||
<slot>
|
||||
<el-dropdown-item command="rename">
|
||||
<i class="el-icon-edit" />
|
||||
{{ $t('chart.rename') }}
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item command="delete">
|
||||
<i class="el-icon-delete" />
|
||||
{{ $t('chart.delete') }}
|
||||
</el-dropdown-item>
|
||||
</slot>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
const { t } = useI18n()
|
||||
const emits = defineEmits(['command'])
|
||||
|
||||
const props = defineProps({
|
||||
model: {
|
||||
type: Object
|
||||
},
|
||||
width: {
|
||||
type: Number
|
||||
}
|
||||
})
|
||||
|
||||
const classBackground = computed(() => {
|
||||
return {
|
||||
width: props.width + 'px',
|
||||
height: props.width * 0.714 + 'px'
|
||||
}
|
||||
})
|
||||
const classImg = computed(() => {
|
||||
return {
|
||||
width: props.width + 'px',
|
||||
height: props.width * 0.576 + 'px'
|
||||
}
|
||||
})
|
||||
|
||||
const handleCommand = key => {
|
||||
emits('command', key)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.de-card-model {
|
||||
box-sizing: border-box;
|
||||
background: #ffffff;
|
||||
border: 1px solid var(--deCardStrokeColor, #dee0e3);
|
||||
border-radius: 4px;
|
||||
margin: 0 24px 25px 0;
|
||||
.card-img-model {
|
||||
border-bottom: 1px solid var(--deCardStrokeColor, #dee0e3);
|
||||
height: 144px;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-top-left-radius: 4px;
|
||||
border-top-right-radius: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.card-info {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 8px 12px 9px 12px;
|
||||
box-sizing: border-box;
|
||||
|
||||
.el-icon-more {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
line-height: 24px;
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
color: #646a73;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.el-icon-more:hover {
|
||||
background: rgba(31, 35, 41, 0.1);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.el-icon-more:active {
|
||||
background: rgba(31, 35, 41, 0.2);
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.de-model-text {
|
||||
font-family: 'PingFang SC';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
color: #1f2329;
|
||||
display: inline-block;
|
||||
width: 90%;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.de-card-model:hover {
|
||||
box-shadow: 0px 6px 24px rgba(31, 35, 41, 0.08);
|
||||
}
|
||||
|
||||
.de-card-dropdown {
|
||||
margin-top: 0 !important;
|
||||
.popper__arrow {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
</style>
|
247
core/core-frontend/src/views/template/component/TemplateList.vue
Normal file
247
core/core-frontend/src/views/template/component/TemplateList.vue
Normal file
@ -0,0 +1,247 @@
|
||||
<template xmlns:el-col="http://www.w3.org/1999/html">
|
||||
<div class="de-template-list">
|
||||
<el-input
|
||||
v-model="state.templateFilterText"
|
||||
:placeholder="t('system_parameter_setting.search_keywords')"
|
||||
size="small"
|
||||
class="de-input-search"
|
||||
clearable
|
||||
>
|
||||
<template #prefix>
|
||||
<svg-icon icon-class="de-search" />
|
||||
</template>
|
||||
</el-input>
|
||||
<el-empty
|
||||
v-if="!templateListComputed.length && state.templateFilterText === ''"
|
||||
:image="state.noneImg"
|
||||
:description="t('components.no_classification')"
|
||||
/>
|
||||
<el-empty
|
||||
v-if="!templateListComputed.length && state.templateFilterText !== ''"
|
||||
:image="state.nothingImg"
|
||||
:description="t('components.relevant_content_found')"
|
||||
/>
|
||||
<ul>
|
||||
<li
|
||||
v-for="ele in templateListComputed"
|
||||
:key="ele.name"
|
||||
:class="[{ select: state.activeTemplate === ele.id }]"
|
||||
@click="nodeClick(ele)"
|
||||
>
|
||||
<svg-icon icon-class="scene" class="de-icon-sense" />
|
||||
<span class="text-template-overflow" :title="ele.name">{{ ele.name }}</span>
|
||||
<span class="more" @click.stop>
|
||||
<el-dropdown trigger="click" size="small" @command="type => clickMore(type, ele)">
|
||||
<span class="el-dropdown-link">
|
||||
<i class="el-icon-more" />
|
||||
</span>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu class="de-template-dropdown">
|
||||
<el-dropdown-item icon="el-icon-upload2" command="import">
|
||||
{{ t('panel.import') }}
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item icon="el-icon-edit" command="edit">
|
||||
{{ t('panel.rename') }}
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item icon="el-icon-delete" command="delete">
|
||||
{{ t('panel.delete') }}
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
<el-button
|
||||
v-if="state.templateFilterText === ''"
|
||||
style="width: 100%"
|
||||
icon="el-icon-plus"
|
||||
secondary
|
||||
@click="add()"
|
||||
>
|
||||
{{ t('panel.add_category') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { computed, reactive } from 'vue'
|
||||
const { t } = useI18n()
|
||||
|
||||
const emits = defineEmits([
|
||||
'showCurrentTemplate',
|
||||
'showTemplateEditDialog',
|
||||
'templateDelete',
|
||||
'templateEdit',
|
||||
'templateImport'
|
||||
])
|
||||
|
||||
const props = defineProps({
|
||||
templateType: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
templateList: {
|
||||
type: Array,
|
||||
default: function () {
|
||||
return []
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const state = reactive({
|
||||
templateFilterText: '',
|
||||
activeTemplate: '',
|
||||
noneImg: '@/assets/None.png',
|
||||
nothingImg: '@/assets/nothing.png'
|
||||
})
|
||||
|
||||
const templateListComputed = computed(() => {
|
||||
if (!state.templateFilterText) return [...props.templateList]
|
||||
return props.templateList.filter(ele => ele['name']?.includes(state.templateFilterText))
|
||||
})
|
||||
|
||||
const clickMore = (type, data) => {
|
||||
switch (type) {
|
||||
case 'edit':
|
||||
templateEdit(data)
|
||||
break
|
||||
case 'delete':
|
||||
templateDelete(data)
|
||||
break
|
||||
case 'import':
|
||||
templateImport(data)
|
||||
break
|
||||
}
|
||||
}
|
||||
const nodeClick = ({ id, label }) => {
|
||||
state.activeTemplate = id
|
||||
emits('showCurrentTemplate', id, label)
|
||||
}
|
||||
const add = () => {
|
||||
emits('showTemplateEditDialog', 'new')
|
||||
}
|
||||
const templateDelete = template => {
|
||||
const options = {
|
||||
title: 'system_parameter_setting.delete_this_category',
|
||||
content: 'system_parameter_setting.also_be_deleted',
|
||||
type: 'primary',
|
||||
cb: () => emits('templateDelete', template.id)
|
||||
}
|
||||
handlerConfirm(options)
|
||||
}
|
||||
const templateEdit = template => {
|
||||
emits('templateEdit', template)
|
||||
}
|
||||
const templateImport = template => {
|
||||
emits('templateImport', template.id)
|
||||
}
|
||||
|
||||
const handlerConfirm = options => {
|
||||
// do handlerConfirm
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.de-template-list {
|
||||
height: 100%;
|
||||
position: relative;
|
||||
|
||||
ul {
|
||||
margin: 16px 0 20px 0;
|
||||
padding: 0;
|
||||
overflow-y: auto;
|
||||
max-height: calc(100% - 90px);
|
||||
}
|
||||
|
||||
li {
|
||||
list-style: none;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
height: 40px;
|
||||
padding: 0 30px 0 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-radius: 4px;
|
||||
color: var(--deTextPrimary, #1f2329);
|
||||
font-family: 'PingFang SC';
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
|
||||
.text-template-overflow {
|
||||
display: inline-block;
|
||||
max-width: 87%;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.folder {
|
||||
color: #8f959e;
|
||||
margin-right: 9px;
|
||||
}
|
||||
|
||||
.more {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 10px;
|
||||
transform: translateY(-50%);
|
||||
display: none;
|
||||
|
||||
.el-icon-more {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
line-height: 24px;
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
color: #646a73;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.el-icon-more:hover {
|
||||
background: rgba(31, 35, 41, 0.1);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.el-icon-more:active {
|
||||
background: rgba(31, 35, 41, 0.2);
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: rgba(31, 35, 41, 0.1);
|
||||
|
||||
.more {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
li.select {
|
||||
background: var(--deWhiteHover, #e0eaff) !important;
|
||||
color: var(--TextActive, #3370ff) !important;
|
||||
}
|
||||
|
||||
.de-btn-fix {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.de-template-dropdown {
|
||||
margin-top: 0 !important;
|
||||
|
||||
.popper__arrow {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,12 +1,412 @@
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue'
|
||||
const wizard = ref('wizard')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
{{ wizard }}
|
||||
<div class="de-template">
|
||||
<el-tabs v-model="state.currentTemplateType" class="de-tabs" @tab-click="handleClick">
|
||||
<el-tab-pane name="self">
|
||||
<template #label>
|
||||
<span>{{ t('panel.user_template') }}</span>
|
||||
</template>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane name="system">
|
||||
<template #label>
|
||||
<span>{{ t('panel.sys_template') }}</span>
|
||||
</template>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
<div class="tabs-container flex-tabs">
|
||||
<div class="de-tabs-left">
|
||||
<template-list
|
||||
ref="templateListRef"
|
||||
:template-type="state.currentTemplateType"
|
||||
:template-list="state.templateList"
|
||||
@templateDelete="templateFolderDelete"
|
||||
@templateEdit="templateEdit"
|
||||
@showCurrentTemplate="showCurrentTemplate"
|
||||
@templateImport="templateImport"
|
||||
@showTemplateEditDialog="showTemplateEditDialog"
|
||||
/>
|
||||
</div>
|
||||
<div class="de-tabs-right">
|
||||
<div v-if="state.currentTemplateLabel" class="active-template">
|
||||
{{ state.currentTemplateLabel }} ({{ state.currentTemplateShowList.length }})
|
||||
<el-button
|
||||
type="primary"
|
||||
icon="el-icon-upload2"
|
||||
@click="templateImport(state.currentTemplateId)"
|
||||
>
|
||||
{{ t('panel.import') }}
|
||||
</el-button>
|
||||
</div>
|
||||
<el-empty
|
||||
v-if="!state.currentTemplateShowList.length"
|
||||
:image="state.noneImg"
|
||||
:description="t('components.no_template')"
|
||||
/>
|
||||
<div v-show="state.currentTemplateId !== ''" id="template-box" class="template-box">
|
||||
<template-item
|
||||
v-for="item in state.currentTemplateShowList"
|
||||
:key="item.id"
|
||||
:width="state.templateCurWidth"
|
||||
:model="item"
|
||||
@command="key => handleCommand(key, item)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-dialog
|
||||
:title="state.dialogTitle"
|
||||
v-model:visible="state.editTemplate"
|
||||
append-to-body
|
||||
class="de-dialog-form"
|
||||
width="600px"
|
||||
>
|
||||
<el-form
|
||||
ref="templateEditFormRef"
|
||||
class="de-form-item"
|
||||
:model="state.templateEditForm"
|
||||
:rules="state.templateEditFormRules"
|
||||
>
|
||||
<el-form-item :label="state.dialogTitleLabel" prop="name">
|
||||
<el-input v-model="state.templateEditForm.name" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button secondary @click="close()">{{ t('commons.cancel') }}</el-button>
|
||||
<el-button type="primary" @click="saveTemplateEdit(state.templateEditForm)"
|
||||
>{{ t('commons.confirm') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!--导入templatedialog-->
|
||||
<el-dialog
|
||||
:title="state.templateDialog.title"
|
||||
v-model:visible="state.templateDialog.visible"
|
||||
:show-close="true"
|
||||
class="de-dialog-form"
|
||||
width="600px"
|
||||
>
|
||||
<template-import
|
||||
v-if="state.templateDialog.visible"
|
||||
:pid="state.templateDialog.pid"
|
||||
@refresh="showCurrentTemplate(state.currentTemplateId, state.currentTemplateLabel)"
|
||||
@closeEditTemplateDialog="closeEditTemplateDialog"
|
||||
/>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped></style>
|
||||
<script lang="ts" setup>
|
||||
import { save, templateDelete, find } from '@/api/template'
|
||||
import elementResizeDetectorMaker from 'element-resize-detector'
|
||||
import { computed, nextTick, onMounted, reactive, ref } from 'vue'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { ElMessage } from 'element-plus-secondary'
|
||||
import TemplateList from '@/views/template/component/TemplateList.vue'
|
||||
const { t } = useI18n()
|
||||
const templateEditFormRef = ref(null)
|
||||
const templateListRef = ref(null)
|
||||
|
||||
const roleValidator = (rule, value, callback) => {
|
||||
if (nameRepeat(value)) {
|
||||
const { nodeType } = state.templateEditForm || {}
|
||||
callback(
|
||||
new Error(
|
||||
t(
|
||||
`system_parameter_setting.${
|
||||
nodeType === 'folder' ? 'name_already_exists_type' : 'the_same_category'
|
||||
}`
|
||||
)
|
||||
)
|
||||
)
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
|
||||
const state = reactive({
|
||||
showShare: false,
|
||||
currentTemplateShowList: [],
|
||||
noneImg: '@/assets/None.png',
|
||||
currentPid: '',
|
||||
currentTemplateType: 'self',
|
||||
templateEditFormRules: {
|
||||
name: [
|
||||
{ required: true, trigger: 'blur', validator: roleValidator },
|
||||
{
|
||||
required: true,
|
||||
message: t('commons.input_content'),
|
||||
trigger: 'blur'
|
||||
},
|
||||
{
|
||||
max: 50,
|
||||
message: t('commons.char_can_not_more_50'),
|
||||
trigger: 'change'
|
||||
}
|
||||
]
|
||||
},
|
||||
templateEditForm: {},
|
||||
editTemplate: false,
|
||||
dialogTitle: '',
|
||||
dialogTitleLabel: '',
|
||||
currentTemplateLabel: '',
|
||||
currentTemplateId: '',
|
||||
templateList: [],
|
||||
templateMiniWidth: 286,
|
||||
templateCurWidth: 286,
|
||||
formType: '',
|
||||
originName: '',
|
||||
templateDialog: {
|
||||
title: t('panel.import_template'),
|
||||
visible: false,
|
||||
pid: ''
|
||||
}
|
||||
})
|
||||
|
||||
const nameList = computed(() => {
|
||||
const { nodeType } = state.templateEditForm || {}
|
||||
if (nodeType === 'template') {
|
||||
return state.currentTemplateShowList.map(ele => ele.label)
|
||||
}
|
||||
|
||||
if (nodeType === 'folder') {
|
||||
return state.templateList.map(ele => ele.label)
|
||||
}
|
||||
return []
|
||||
})
|
||||
|
||||
const nameRepeat = value => {
|
||||
if (!nameList.value) {
|
||||
return false
|
||||
}
|
||||
// 编辑场景 不能 因为名称重复而报错
|
||||
if (state.formType === 'edit' && state.originName === value) {
|
||||
return false
|
||||
}
|
||||
return nameList.value.some(name => name === value)
|
||||
}
|
||||
|
||||
const handleCommand = (key, data) => {
|
||||
switch (key) {
|
||||
case 'rename':
|
||||
templateEdit(data)
|
||||
break
|
||||
case 'delete':
|
||||
templateDeleteConfirm(data)
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
const handlerConfirm = option => {
|
||||
//do handlerConfirm
|
||||
}
|
||||
|
||||
const templateDeleteConfirm = template => {
|
||||
const options = {
|
||||
title: 'system_parameter_setting.delete_this_template',
|
||||
type: 'primary',
|
||||
cb: () => templateDelete(template.id)
|
||||
}
|
||||
handlerConfirm(options)
|
||||
}
|
||||
|
||||
const handleClick = (tab, event) => {
|
||||
getTree()
|
||||
}
|
||||
|
||||
const showCurrentTemplate = (pid, label) => {
|
||||
state.currentTemplateId = pid
|
||||
state.currentTemplateLabel = label
|
||||
if (state.currentTemplateId) {
|
||||
find({ pid: state.currentTemplateId }).then(response => {
|
||||
state.currentTemplateShowList = response.data
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const templateFolderDelete = id => {
|
||||
if (id) {
|
||||
templateDelete(id).then(response => {
|
||||
ElMessage.info(t('commons.delete_success'))
|
||||
getTree()
|
||||
})
|
||||
}
|
||||
}
|
||||
const templateDelete = id => {
|
||||
if (id) {
|
||||
templateDelete(id).then(response => {
|
||||
ElMessage.info(t('commons.delete_success'))
|
||||
showCurrentTemplate(state.currentTemplateId, state.currentTemplateLabel)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const showTemplateEditDialog = (type, templateInfo) => {
|
||||
state.templateEditForm = null
|
||||
state.formType = type
|
||||
if (type === 'edit') {
|
||||
state.templateEditForm = JSON.parse(JSON.stringify(templateInfo))
|
||||
state.dialogTitle = t(
|
||||
`system_parameter_setting.${
|
||||
state.templateEditForm['nodeType'] === 'folder' ? 'edit_classification' : 'edit_template'
|
||||
}`
|
||||
)
|
||||
state.originName = state.templateEditForm['label']
|
||||
} else {
|
||||
state.dialogTitle = t('panel.add_category')
|
||||
state.templateEditForm = {
|
||||
name: '',
|
||||
nodeType: 'folder',
|
||||
templateType: state.currentTemplateType,
|
||||
level: 0
|
||||
}
|
||||
}
|
||||
state.dialogTitleLabel = t(
|
||||
`system_parameter_setting.${
|
||||
state.templateEditForm['nodeType'] === 'folder' ? 'classification_name' : 'template_name'
|
||||
}`
|
||||
)
|
||||
state.editTemplate = true
|
||||
}
|
||||
|
||||
const templateEdit = templateInfo => {
|
||||
showTemplateEditDialog('edit', templateInfo)
|
||||
}
|
||||
|
||||
const saveTemplateEdit = templateEditForm => {
|
||||
templateEditFormRef.value.validate(valid => {
|
||||
if (valid) {
|
||||
save(templateEditForm).then(response => {
|
||||
close()
|
||||
// openMessageSuccess(
|
||||
// `system_parameter_setting.${
|
||||
// this.templateEditForm.id ? 'rename_succeeded' : 'added_successfully'
|
||||
// }`
|
||||
// )
|
||||
getTree()
|
||||
})
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
})
|
||||
}
|
||||
const close = () => {
|
||||
templateEditFormRef.value.resetFields()
|
||||
state.editTemplate = false
|
||||
}
|
||||
const getTree = () => {
|
||||
const request = {
|
||||
templateType: state.currentTemplateType,
|
||||
level: '0'
|
||||
}
|
||||
find(request).then(res => {
|
||||
state.templateList = res.data
|
||||
showFirst()
|
||||
})
|
||||
}
|
||||
const showFirst = () => {
|
||||
// 判断是否默认点击第一条
|
||||
if (state.templateList && state.templateList.length > 0) {
|
||||
let showFirst = true
|
||||
state.templateList.forEach(template => {
|
||||
if (template.id === state.currentTemplateId) {
|
||||
showFirst = false
|
||||
}
|
||||
})
|
||||
if (showFirst) {
|
||||
nextTick().then(() => {
|
||||
const [obj = {}] = state.templateList
|
||||
templateListRef.value.nodeClick(obj)
|
||||
})
|
||||
} else {
|
||||
showCurrentTemplate(state.currentTemplateId, state.currentTemplateLabel)
|
||||
}
|
||||
} else {
|
||||
state.currentTemplateShowList = []
|
||||
}
|
||||
}
|
||||
|
||||
const closeEditTemplateDialog = () => {
|
||||
state.templateDialog.visible = false
|
||||
}
|
||||
|
||||
const templateImport = pid => {
|
||||
state.templateDialog.visible = true
|
||||
state.templateDialog.pid = pid
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getTree()
|
||||
const erd = elementResizeDetectorMaker()
|
||||
const templateMainDom = document.getElementById('template-box')
|
||||
// 监听div变动事件
|
||||
erd.listenTo(templateMainDom, element => {
|
||||
nextTick(() => {
|
||||
const curSeparator = Math.trunc(templateMainDom.offsetWidth / state.templateMiniWidth)
|
||||
state.templateCurWidth =
|
||||
Math.trunc(templateMainDom.offsetWidth / curSeparator) - 24 - curSeparator
|
||||
})
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.de-template {
|
||||
height: 100%;
|
||||
background-color: var(--MainBG, #f5f6f7);
|
||||
|
||||
.tabs-container {
|
||||
height: calc(100% - 48px);
|
||||
background: var(--ContentBG, #ffffff);
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.flex-tabs {
|
||||
display: flex;
|
||||
background: #f5f6f7;
|
||||
}
|
||||
|
||||
.de-tabs-left {
|
||||
background: #fff;
|
||||
width: 269px;
|
||||
border-right: 1px solid rgba(31, 35, 41, 0.15);
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
.de-tabs-right {
|
||||
flex: 1;
|
||||
background: #fff;
|
||||
padding: 24px 0 24px 24px;
|
||||
overflow: hidden;
|
||||
|
||||
.template-box {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
overflow-y: auto;
|
||||
box-sizing: border-box;
|
||||
align-content: flex-start;
|
||||
height: calc(100% - 10px);
|
||||
width: 100%;
|
||||
padding-bottom: 24px;
|
||||
}
|
||||
|
||||
.active-template {
|
||||
margin: 4px 0 20px 0;
|
||||
padding-right: 24px;
|
||||
font-family: 'PingFang SC';
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-size: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
color: var(--deTextPrimary, #1f2329);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -336,8 +336,9 @@ const getEmptyDesc = (): string => {
|
||||
padding: 8px 24px 0 24px;
|
||||
background: #fff;
|
||||
border-radius: 4px;
|
||||
height: calc(100% - 280px);
|
||||
margin-top: 16px;
|
||||
// height: calc(100% - 280px);
|
||||
// margin-top: 16px;
|
||||
height: 100%;
|
||||
|
||||
.select-type-list {
|
||||
width: 104px;
|
||||
|
@ -17,6 +17,8 @@ const { t } = useI18n()
|
||||
const busiDataMap = computed(() => interactiveStore.getData)
|
||||
const busiCountCardList = ref([])
|
||||
|
||||
const showTemplate = ref(false)
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
const quickCreationList = shallowRef([
|
||||
@ -159,7 +161,7 @@ fillCardInfo()
|
||||
</div>
|
||||
</div>
|
||||
<div class="template-market-dashboard">
|
||||
<div class="template-market">
|
||||
<div v-if="showTemplate" class="template-market">
|
||||
<div class="label">
|
||||
模版市场
|
||||
<div class="expand-all">
|
||||
|
2
de-xpack
2
de-xpack
@ -1 +1 @@
|
||||
Subproject commit c2c4436bac4d300e5297ff1854fd6d45e01435ad
|
||||
Subproject commit 3850e6d19884be36d24dea6589552d66b5675eea
|
@ -1,4 +1,4 @@
|
||||
pisix:
|
||||
apisix:
|
||||
node_listen: 9080 # APISIX listening port
|
||||
enable_ipv6: false
|
||||
|
||||
|
@ -2,7 +2,7 @@ version: "3"
|
||||
|
||||
services:
|
||||
apisix-dashboard:
|
||||
image: apache/apisix-dashboard:3.0.1-alpine
|
||||
image: registry.cn-qingdao.aliyuncs.com/dataease/apisix-dashboard:3.0.1-alpine
|
||||
container_name: apisix-dashboard
|
||||
restart: always
|
||||
volumes:
|
||||
@ -13,7 +13,7 @@ services:
|
||||
dataease-network:
|
||||
|
||||
apisix:
|
||||
image: apache/apisix:3.4.1-debian
|
||||
image: registry.cn-qingdao.aliyuncs.com/dataease/apisix:3.6.0-debian
|
||||
container_name: apisix
|
||||
environment:
|
||||
- TZ=Asia/Shanghai
|
||||
@ -33,7 +33,7 @@ services:
|
||||
dataease-network:
|
||||
|
||||
etcd:
|
||||
image: bitnami/etcd:3.4.15
|
||||
image: registry.cn-qingdao.aliyuncs.com/dataease/etcd:3.5.10
|
||||
container_name: apisix-etcd
|
||||
restart: always
|
||||
volumes:
|
||||
|
@ -2,7 +2,7 @@ version: '2.1'
|
||||
services:
|
||||
|
||||
DE_MYSQL_HOST:
|
||||
image: mysql:8.1.0
|
||||
image: registry.cn-qingdao.aliyuncs.com/dataease/mysql:8.1.0
|
||||
container_name: ${DE_MYSQL_HOST}
|
||||
healthcheck:
|
||||
test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost", "-u${DE_MYSQL_USER}", "-p${DE_MYSQL_PASSWORD}", "--protocol","tcp"]
|
||||
|
@ -2,7 +2,7 @@ version: '2.1'
|
||||
services:
|
||||
|
||||
dataease:
|
||||
image: registry.cn-qingdao.aliyuncs.com/dataease/dataease2.0:DE_TAG
|
||||
image: registry.cn-qingdao.aliyuncs.com/dataease/dataease:DE_TAG
|
||||
container_name: dataease
|
||||
ports:
|
||||
- ${DE_PORT}:8100
|
||||
|
@ -14,4 +14,4 @@ dataease:
|
||||
origin-list: localhost:8080,localhost:8100,localhost:9080
|
||||
apisix-api:
|
||||
domain: http://apisix:9180
|
||||
key: edd1c9f034335f136f87ad84b625c8f1
|
||||
key: DE_APISIX_KEY
|
@ -44,7 +44,7 @@ function usage() {
|
||||
echo " version 查看 DATAEASE 版本"
|
||||
}
|
||||
function _check_apisix_init() {
|
||||
if [[ $DE_INSTALL_MODE = "enterprise" ]];then
|
||||
if [[ $DE_INSTALL_MODE != "community" ]];then
|
||||
_prepare_apisix
|
||||
fi
|
||||
}
|
||||
@ -56,7 +56,7 @@ function _prepare_apisix() {
|
||||
cd $DE_RUNNING_BASE
|
||||
env | grep DE_ >.env
|
||||
sed -i -e "s/DE_APISIX_KEY/${DE_APISIX_KEY}/g" $DE_RUNNING_BASE/apisix/apisix_conf/config.yaml
|
||||
sed -i -e "s/key:.*/key: ${DE_APISIX_KEY}/g" $DE_RUNNING_BASE/conf/application.yml
|
||||
sed -i -e "s/DE_APISIX_KEY/${DE_APISIX_KEY}/g" $DE_RUNNING_BASE/conf/application.yml
|
||||
fi
|
||||
compose_files="${compose_files} -f docker-compose-apisix.yml"
|
||||
}
|
||||
@ -83,7 +83,7 @@ function _healthcheck() {
|
||||
echo
|
||||
}
|
||||
function _get_current_version() {
|
||||
de_current_version=$(grep "^ image:.*dataease2.0:" ${DE_RUNNING_BASE}/docker-compose.yml | awk -F'dataease2.0:' '{print $2}')
|
||||
de_current_version=$(grep "^ image:.*dataease:" ${DE_RUNNING_BASE}/docker-compose.yml | awk -F'dataease:' '{print $2}')
|
||||
echo $de_current_version
|
||||
}
|
||||
function status() {
|
||||
@ -143,7 +143,7 @@ function version() {
|
||||
}
|
||||
function upgrade() {
|
||||
echo
|
||||
git_urls=('gitee.com' 'github.com')
|
||||
git_urls=('github.com')
|
||||
if [[ -x "$(command -v python)" ]]; then
|
||||
py_cmd='python'
|
||||
elif [[ -x "$(command -v python3)" ]]; then
|
||||
@ -170,7 +170,7 @@ function upgrade() {
|
||||
done
|
||||
|
||||
if [[ "x${server_url}" == "x" ]]; then
|
||||
echo "没有找到稳定的下载服务器,请稍候重试"
|
||||
echo "没有找到稳定的下载服务器,请访问 https://community.fit2cloud.com/#/products/dataease/downloads 下载离线安装包"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
@ -6,7 +6,7 @@ DE_PORT=8100
|
||||
## 登录超时时间,单位min。如果不设置则默认8小时,也就是480
|
||||
DE_LOGIN_TIMEOUT=480
|
||||
## 安装模式
|
||||
DE_INSTALL_MODE=enterprise
|
||||
DE_INSTALL_MODE=community
|
||||
|
||||
# 数据库配置
|
||||
## 是否使用外部数据库
|
||||
|
@ -183,7 +183,7 @@ else
|
||||
cd ${DE_RUN_BASE} && docker-compose $compose_files pull 2>&1
|
||||
|
||||
DEVERSION=$(cat ${CURRENT_DIR}/dataease/templates/version)
|
||||
#curl -sfL https://resource.fit2cloud.com/installation-log.sh | sh -s de ${INSTALL_TYPE} ${DEVERSION}
|
||||
curl -sfL https://resource.fit2cloud.com/installation-log.sh | sh -s de ${INSTALL_TYPE} ${DEVERSION}
|
||||
cd -
|
||||
fi
|
||||
|
||||
@ -258,5 +258,4 @@ if [[ $http_code != 200 ]];then
|
||||
fi
|
||||
|
||||
echo -e "======================= 安装完成 =======================\n" 2>&1 | tee -a ${CURRENT_DIR}/install.log
|
||||
echo -e "请通过以下方式访问:\n URL: http://\$LOCAL_IP:$DE_PORT\n 用户名: admin\n 初始密码: dataease" 2>&1 | tee -a ${CURRENT_DIR}/install.log
|
||||
|
||||
|
@ -0,0 +1,13 @@
|
||||
package io.dataease.api.template;
|
||||
|
||||
import io.dataease.api.template.dto.TemplateManageDTO;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface TemplateManageApi {
|
||||
|
||||
@PostMapping("/templateList")
|
||||
List<TemplateManageDTO> templateList();
|
||||
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package io.dataease.api.template;
|
||||
|
||||
import io.dataease.api.template.request.TemplateMarketSearchRequest;
|
||||
import io.dataease.api.template.response.MarketBaseResponse;
|
||||
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;
|
||||
|
||||
/**
|
||||
* @author : WangJiaHao
|
||||
* @date : 2023/11/6 17:23
|
||||
*/
|
||||
public interface TemplateMarketApi {
|
||||
|
||||
@PostMapping("/search")
|
||||
MarketBaseResponse searchTemplate(@RequestBody TemplateMarketSearchRequest request);
|
||||
|
||||
@GetMapping("/categories")
|
||||
List<String> categories();
|
||||
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package io.dataease.api.template.dto;
|
||||
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
|
||||
|
||||
@Data
|
||||
public class TemplateManageDTO {
|
||||
|
||||
private String label;
|
||||
private Integer childrenCount;
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package io.dataease.api.template.dto;
|
||||
|
||||
import io.dataease.api.template.vo.MarketCategoryVO;
|
||||
import io.dataease.api.template.vo.MarketMetasVO;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class TemplateMarketDTO {
|
||||
private String id;
|
||||
private String title;
|
||||
private String status;
|
||||
private String slug;
|
||||
private String editorType;
|
||||
private String summary;
|
||||
private String thumbnail;
|
||||
private Boolean showFlag = true;
|
||||
private List<MarketCategoryVO> categories;
|
||||
private MarketMetasVO metas;
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package io.dataease.api.template.request;
|
||||
|
||||
import io.dataease.api.template.dto.TemplateMarketDTO;
|
||||
|
||||
public class TemplateMarketSearchRequest extends TemplateMarketDTO {
|
||||
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package io.dataease.api.template.response;
|
||||
|
||||
import io.dataease.api.template.dto.TemplateMarketDTO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author : WangJiaHao
|
||||
* @date : 2023/11/6 17:43
|
||||
*/
|
||||
public class MarketBaseResponse {
|
||||
private String baseUrl;
|
||||
|
||||
private List<TemplateMarketDTO> contents;
|
||||
|
||||
public MarketBaseResponse() {
|
||||
}
|
||||
|
||||
public MarketBaseResponse(String baseUrl, List<TemplateMarketDTO> contents) {
|
||||
this.baseUrl = baseUrl;
|
||||
this.contents = contents;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package io.dataease.api.template.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* Author: wangjiahao
|
||||
* Date: 2022/7/15
|
||||
* Description:
|
||||
*/
|
||||
@Data
|
||||
public class MarketCategoryVO {
|
||||
private String id;
|
||||
private String name;
|
||||
private String slug;
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package io.dataease.api.template.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* Author: wangjiahao
|
||||
* Date: 2022/7/15
|
||||
* Description:
|
||||
*/
|
||||
@Data
|
||||
public class MarketMetasVO {
|
||||
private String theme_repo;
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package io.dataease.api.template.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* Author: wangjiahao
|
||||
* Date: 2022/7/18
|
||||
* Description:
|
||||
*/
|
||||
@Data
|
||||
public class TemplateCategoryVO {
|
||||
private Integer id;
|
||||
|
||||
private String name;
|
||||
|
||||
private String slug;
|
||||
|
||||
private Integer priority;
|
||||
}
|
@ -1,11 +1,14 @@
|
||||
package io.dataease.utils;
|
||||
|
||||
import org.springframework.core.env.Environment;
|
||||
|
||||
public class VersionUtil {
|
||||
|
||||
private static final String randomId = IDUtils.randomID(16);
|
||||
|
||||
public static String getRandomVersion() {
|
||||
return randomId;
|
||||
Environment environment = CommonBeanFactory.getBean(Environment.class);
|
||||
assert environment != null;
|
||||
return environment.getProperty("dataease.version", "2.0.0");
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user