forked from github/dataease
Merge pull request #6581 from dataease/pr@dev-v2@feat_template-market
feat: 模版市场
This commit is contained in:
commit
466aecc512
@ -0,0 +1,206 @@
|
||||
package io.dataease.template.dao.auto.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 仪表板模板表
|
||||
* </p>
|
||||
*
|
||||
* @author fit2cloud
|
||||
* @since 2023-11-06
|
||||
*/
|
||||
@TableName("visualization_template")
|
||||
public class VisualizationTemplate implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* 名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 父级id
|
||||
*/
|
||||
private String pid;
|
||||
|
||||
/**
|
||||
* 层级
|
||||
*/
|
||||
private Integer level;
|
||||
|
||||
/**
|
||||
* 模版种类 dataV or dashboard 目录或者文件夹
|
||||
*/
|
||||
private String dvType;
|
||||
|
||||
/**
|
||||
* 节点类型 folder or panel 目录或者文件夹
|
||||
*/
|
||||
private String nodeType;
|
||||
|
||||
/**
|
||||
* 创建人
|
||||
*/
|
||||
private String createBy;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private Long createTime;
|
||||
|
||||
/**
|
||||
* 缩略图
|
||||
*/
|
||||
private String snapshot;
|
||||
|
||||
/**
|
||||
* 模版类型 system 系统内置 self 用户自建
|
||||
*/
|
||||
private String templateType;
|
||||
|
||||
/**
|
||||
* template 样式
|
||||
*/
|
||||
private String templateStyle;
|
||||
|
||||
/**
|
||||
* template 数据
|
||||
*/
|
||||
private String templateData;
|
||||
|
||||
/**
|
||||
* 预存数据
|
||||
*/
|
||||
private String dynamicData;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getPid() {
|
||||
return pid;
|
||||
}
|
||||
|
||||
public void setPid(String pid) {
|
||||
this.pid = pid;
|
||||
}
|
||||
|
||||
public Integer getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
public void setLevel(Integer level) {
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
public String getDvType() {
|
||||
return dvType;
|
||||
}
|
||||
|
||||
public void setDvType(String dvType) {
|
||||
this.dvType = dvType;
|
||||
}
|
||||
|
||||
public String getNodeType() {
|
||||
return nodeType;
|
||||
}
|
||||
|
||||
public void setNodeType(String nodeType) {
|
||||
this.nodeType = nodeType;
|
||||
}
|
||||
|
||||
public String getCreateBy() {
|
||||
return createBy;
|
||||
}
|
||||
|
||||
public void setCreateBy(String createBy) {
|
||||
this.createBy = createBy;
|
||||
}
|
||||
|
||||
public Long getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
public void setCreateTime(Long createTime) {
|
||||
this.createTime = createTime;
|
||||
}
|
||||
|
||||
public String getSnapshot() {
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
public void setSnapshot(String snapshot) {
|
||||
this.snapshot = snapshot;
|
||||
}
|
||||
|
||||
public String getTemplateType() {
|
||||
return templateType;
|
||||
}
|
||||
|
||||
public void setTemplateType(String templateType) {
|
||||
this.templateType = templateType;
|
||||
}
|
||||
|
||||
public String getTemplateStyle() {
|
||||
return templateStyle;
|
||||
}
|
||||
|
||||
public void setTemplateStyle(String templateStyle) {
|
||||
this.templateStyle = templateStyle;
|
||||
}
|
||||
|
||||
public String getTemplateData() {
|
||||
return templateData;
|
||||
}
|
||||
|
||||
public void setTemplateData(String templateData) {
|
||||
this.templateData = templateData;
|
||||
}
|
||||
|
||||
public String getDynamicData() {
|
||||
return dynamicData;
|
||||
}
|
||||
|
||||
public void setDynamicData(String dynamicData) {
|
||||
this.dynamicData = dynamicData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "VisualizationTemplate{" +
|
||||
"id = " + id +
|
||||
", name = " + name +
|
||||
", pid = " + pid +
|
||||
", level = " + level +
|
||||
", dvType = " + dvType +
|
||||
", nodeType = " + nodeType +
|
||||
", createBy = " + createBy +
|
||||
", createTime = " + createTime +
|
||||
", snapshot = " + snapshot +
|
||||
", templateType = " + templateType +
|
||||
", templateStyle = " + templateStyle +
|
||||
", templateData = " + templateData +
|
||||
", dynamicData = " + dynamicData +
|
||||
"}";
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package io.dataease.template.dao.auto.mapper;
|
||||
|
||||
import io.dataease.template.dao.auto.entity.VisualizationTemplate;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 仪表板模板表 Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author fit2cloud
|
||||
* @since 2023-11-06
|
||||
*/
|
||||
@Mapper
|
||||
public interface VisualizationTemplateMapper extends BaseMapper<VisualizationTemplate> {
|
||||
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package io.dataease.template.dao.ext;
|
||||
|
||||
import io.dataease.api.template.dto.TemplateManageDTO;
|
||||
import io.dataease.api.template.request.TemplateManageRequest;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@Mapper
|
||||
public interface ExtVisualizationTemplateMapper{
|
||||
|
||||
List<TemplateManageDTO> findTemplateList(TemplateManageRequest request);
|
||||
|
||||
}
|
@ -0,0 +1,150 @@
|
||||
package io.dataease.template.service;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import io.dataease.api.template.dto.TemplateManageDTO;
|
||||
import io.dataease.api.template.request.TemplateManageRequest;
|
||||
import io.dataease.api.template.vo.VisualizationTemplateVO;
|
||||
import io.dataease.constant.CommonConstants;
|
||||
import io.dataease.exception.DEException;
|
||||
import io.dataease.template.dao.auto.entity.VisualizationTemplate;
|
||||
import io.dataease.template.dao.auto.mapper.VisualizationTemplateMapper;
|
||||
import io.dataease.template.dao.ext.ExtVisualizationTemplateMapper;
|
||||
import io.dataease.utils.AuthUtils;
|
||||
import io.dataease.utils.BeanUtils;
|
||||
import io.dataease.visualization.server.StaticResourceServer;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
import static io.dataease.constant.StaticResourceConstants.UPLOAD_URL_PREFIX;
|
||||
|
||||
/**
|
||||
* @author : WangJiaHao
|
||||
* @date : 2023/11/7 13:29
|
||||
*/
|
||||
public class TemplateManageService {
|
||||
|
||||
@Resource
|
||||
private VisualizationTemplateMapper templateMapper;
|
||||
@Resource
|
||||
private ExtVisualizationTemplateMapper extTemplateMapper;
|
||||
@Resource
|
||||
private StaticResourceServer staticResourceServer;
|
||||
|
||||
public List<TemplateManageDTO> templateList(TemplateManageRequest request) {
|
||||
request.setWithBlobs("N");
|
||||
List<TemplateManageDTO> templateList = extTemplateMapper.findTemplateList(request);
|
||||
if (request.getWithChildren()) {
|
||||
getTreeChildren(templateList);
|
||||
}
|
||||
return templateList;
|
||||
}
|
||||
|
||||
public void getTreeChildren(List<TemplateManageDTO> parentTemplateList) {
|
||||
Optional.ofNullable(parentTemplateList).ifPresent(parent -> parent.forEach(parentTemplate -> {
|
||||
List<TemplateManageDTO> panelTemplateDTOChildren = extTemplateMapper.findTemplateList(new TemplateManageRequest(parentTemplate.getId()));
|
||||
parentTemplate.setChildren(panelTemplateDTOChildren);
|
||||
getTreeChildren(panelTemplateDTOChildren);
|
||||
}));
|
||||
}
|
||||
|
||||
public List<TemplateManageDTO> getSystemTemplateType(TemplateManageRequest request) {
|
||||
return extTemplateMapper.findTemplateList(request);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public TemplateManageDTO save(TemplateManageRequest request) {
|
||||
if (StringUtils.isEmpty(request.getId())) {
|
||||
request.setId(UUID.randomUUID().toString());
|
||||
request.setCreateTime(System.currentTimeMillis());
|
||||
request.setCreateBy(AuthUtils.getUser().getUserId().toString());
|
||||
//如果level 是0(第一级)指的是分类目录 设置父级为对应的templateType
|
||||
if (request.getLevel() == 0) {
|
||||
request.setPid(request.getTemplateType());
|
||||
String nameCheckResult = this.nameCheck(CommonConstants.OPT_TYPE.INSERT, request.getName(), request.getPid(), null);
|
||||
if (CommonConstants.CHECK_RESULT.EXIST_ALL.equals(nameCheckResult)) {
|
||||
DEException.throwException("名称已存在");
|
||||
}
|
||||
} else {//模板插入 相同文件夹同名的模板进行覆盖(先删除)
|
||||
QueryWrapper<VisualizationTemplate> wrapper = new QueryWrapper<>();
|
||||
wrapper.eq("pid",request.getPid());
|
||||
wrapper.eq("name",request.getName());
|
||||
templateMapper.delete(wrapper);
|
||||
}
|
||||
if ("template".equals(request.getNodeType())) {
|
||||
//Store static resource into the server
|
||||
staticResourceServer.saveFilesToServe(request.getStaticResource());
|
||||
String snapshotName = "template-" + request.getId() + ".jpeg";
|
||||
staticResourceServer.saveSingleFileToServe(snapshotName, request.getSnapshot().replace("data:image/jpeg;base64,", ""));
|
||||
request.setSnapshot("/" + UPLOAD_URL_PREFIX + '/' + snapshotName);
|
||||
}
|
||||
|
||||
VisualizationTemplate template = new VisualizationTemplate();
|
||||
BeanUtils.copyBean(template,request);
|
||||
templateMapper.insert(template);
|
||||
} else {
|
||||
String nameCheckResult = this.nameCheck(CommonConstants.OPT_TYPE.UPDATE, request.getName(), request.getPid(), request.getId());
|
||||
if (CommonConstants.CHECK_RESULT.EXIST_ALL.equals(nameCheckResult)) {
|
||||
DEException.throwException("名称已存在");
|
||||
}
|
||||
VisualizationTemplate template = new VisualizationTemplate();
|
||||
BeanUtils.copyBean(template,request);
|
||||
templateMapper.updateById(template);
|
||||
}
|
||||
TemplateManageDTO templateManageDTO = new TemplateManageDTO();
|
||||
BeanUtils.copyBean(templateManageDTO, request);
|
||||
templateManageDTO.setLabel(request.getName());
|
||||
return templateManageDTO;
|
||||
}
|
||||
|
||||
//名称检查
|
||||
public String nameCheck(String optType, String name, String pid, String id) {
|
||||
QueryWrapper<VisualizationTemplate> wrapper = new QueryWrapper<>();
|
||||
if (CommonConstants.OPT_TYPE.INSERT.equals(optType)) {
|
||||
wrapper.eq("pid",pid);
|
||||
wrapper.eq("name",name);
|
||||
} else if (CommonConstants.OPT_TYPE.UPDATE.equals(optType)) {
|
||||
wrapper.eq("pid",pid);
|
||||
wrapper.eq("name",name);
|
||||
wrapper.ne("id",id);
|
||||
}
|
||||
List<VisualizationTemplate> templateList = templateMapper.selectList(wrapper);
|
||||
if (CollectionUtils.isEmpty(templateList)) {
|
||||
return CommonConstants.CHECK_RESULT.NONE;
|
||||
} else {
|
||||
return CommonConstants.CHECK_RESULT.EXIST_ALL;
|
||||
}
|
||||
}
|
||||
|
||||
public String nameCheck(TemplateManageRequest request) {
|
||||
return nameCheck(request.getOptType(), request.getName(), request.getPid(), request.getId());
|
||||
|
||||
}
|
||||
|
||||
public void delete(String id) {
|
||||
Assert.notNull(id, "id cannot be null");
|
||||
templateMapper.deleteById(id);
|
||||
}
|
||||
|
||||
public VisualizationTemplateVO findOne(String panelId) {
|
||||
VisualizationTemplate template = templateMapper.selectById(panelId);
|
||||
if(template != null){
|
||||
VisualizationTemplateVO templateVO = new VisualizationTemplateVO();
|
||||
BeanUtils.copyBean(templateVO,template);
|
||||
return templateVO;
|
||||
}else{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public List<TemplateManageDTO> find(TemplateManageRequest request) {
|
||||
return extTemplateMapper.findTemplateList(request);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
DROP TABLE IF EXISTS `visualization_template`;
|
||||
CREATE TABLE `visualization_template` (
|
||||
`id` varchar(50) NOT NULL COMMENT '主键',
|
||||
`name` varchar(255) DEFAULT NULL COMMENT '名称',
|
||||
`pid` varchar(255) DEFAULT NULL COMMENT '父级id',
|
||||
`level` int(10) DEFAULT NULL COMMENT '层级',
|
||||
`dv_type` varchar(255) DEFAULT NULL COMMENT '模版种类 dataV or dashboard 目录或者文件夹',
|
||||
`node_type` varchar(255) DEFAULT NULL COMMENT '节点类型 folder or panel 目录或者文件夹',
|
||||
`create_by` varchar(255) DEFAULT NULL COMMENT '创建人',
|
||||
`create_time` bigint(13) DEFAULT NULL COMMENT '创建时间',
|
||||
`snapshot` longtext COMMENT '缩略图',
|
||||
`template_type` varchar(255) DEFAULT NULL COMMENT '模版类型 system 系统内置 self 用户自建 ',
|
||||
`template_style` longtext COMMENT 'template 样式',
|
||||
`template_data` longtext COMMENT 'template 数据',
|
||||
`dynamic_data` longtext COMMENT '预存数据',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='模板表';
|
@ -0,0 +1,17 @@
|
||||
DROP TABLE IF EXISTS `visualization_template`;
|
||||
CREATE TABLE `visualization_template` (
|
||||
`id` varchar(50) NOT NULL COMMENT '主键',
|
||||
`name` varchar(255) DEFAULT NULL COMMENT '名称',
|
||||
`pid` varchar(255) DEFAULT NULL COMMENT '父级id',
|
||||
`level` int(10) DEFAULT NULL COMMENT '层级',
|
||||
`dv_type` varchar(255) DEFAULT NULL COMMENT '模版种类 dataV or dashboard 目录或者文件夹',
|
||||
`node_type` varchar(255) DEFAULT NULL COMMENT '节点类型 folder or panel 目录或者文件夹',
|
||||
`create_by` varchar(255) DEFAULT NULL COMMENT '创建人',
|
||||
`create_time` bigint(13) DEFAULT NULL COMMENT '创建时间',
|
||||
`snapshot` longtext COMMENT '缩略图',
|
||||
`template_type` varchar(255) DEFAULT NULL COMMENT '模版类型 system 系统内置 self 用户自建 ',
|
||||
`template_style` longtext COMMENT 'template 样式',
|
||||
`template_data` longtext COMMENT 'template 数据',
|
||||
`dynamic_data` longtext COMMENT '预存数据',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='模板表';
|
@ -0,0 +1,494 @@
|
||||
<script lang="ts" setup>
|
||||
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
|
||||
import { snapshotStoreWithOut } from '@/store/modules/data-visualization/snapshot'
|
||||
import { layerStoreWithOut } from '@/store/modules/data-visualization/layer'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { ElCol, ElIcon, ElRow } from 'element-plus-secondary'
|
||||
import Icon from '../icon-custom/src/Icon.vue'
|
||||
import { computed, nextTick, ref } from 'vue'
|
||||
import draggable from 'vuedraggable'
|
||||
import { lockStoreWithOut } from '@/store/modules/data-visualization/lock'
|
||||
import ContextMenuAsideDetails from '@/components/data-visualization/canvas/ContextMenuAsideDetails.vue'
|
||||
import ComposeShow from '@/components/data-visualization/canvas/ComposeShow.vue'
|
||||
import { composeStoreWithOut } from '@/store/modules/data-visualization/compose'
|
||||
import { contextmenuStoreWithOut } from '@/store/modules/data-visualization/contextmenu'
|
||||
const dropdownMore = ref(null)
|
||||
const lockStore = lockStoreWithOut()
|
||||
|
||||
const dvMainStore = dvMainStoreWithOut()
|
||||
const snapshotStore = snapshotStoreWithOut()
|
||||
const layerStore = layerStoreWithOut()
|
||||
const composeStore = composeStoreWithOut()
|
||||
const contextmenuStore = contextmenuStoreWithOut()
|
||||
|
||||
const { areaData, isCtrlOrCmdDown, isShiftDown, laterIndex } = storeToRefs(composeStore)
|
||||
|
||||
const { componentData, curComponent, curComponentIndex, canvasViewInfo } = storeToRefs(dvMainStore)
|
||||
const getComponent = index => {
|
||||
return componentData.value[componentData.value.length - 1 - index]
|
||||
}
|
||||
const transformIndex = index => {
|
||||
return componentData.value.length - 1 - index
|
||||
}
|
||||
const areaDataPush = component => {
|
||||
if (component && !component.isLock && component.isShow) {
|
||||
areaData.value.components.push(component)
|
||||
}
|
||||
}
|
||||
// shift 选择算法逻辑
|
||||
// 1.记录上次点击的laterIndex(初始状态laterIndex=0);
|
||||
// 2.获取当前index curClickIndex;
|
||||
// 3.比较laterIndex 和 curClickIndex之间的大小;
|
||||
// 4.将[laterIndex,curClickIndex] 或者 [curClickIndex,laterIndex]区域的图层加入areaData.value.components(已包含的不再重复加入);
|
||||
const shiftDataPush = curClickIndex => {
|
||||
const areaDataIdArray = areaData.value.components.map(com => com.id)
|
||||
let indexBegin, indexEnd
|
||||
const laterIndexTrans = laterIndex.value === null ? componentData.value.length : laterIndex.value
|
||||
if (laterIndexTrans < curClickIndex) {
|
||||
indexBegin = laterIndexTrans
|
||||
indexEnd = curClickIndex
|
||||
} else {
|
||||
indexBegin = curClickIndex
|
||||
indexEnd = laterIndexTrans
|
||||
}
|
||||
const shiftAreaComponents = componentData.value
|
||||
.slice(indexBegin, indexEnd + 1)
|
||||
.filter(
|
||||
component => !areaDataIdArray.includes(component.id) && !component.isLock && component.isShow
|
||||
)
|
||||
areaData.value.components.push(...shiftAreaComponents)
|
||||
dvMainStore.setCurComponent({ component: null, index: null })
|
||||
}
|
||||
|
||||
const onClick = (e, index) => {
|
||||
// 初始化点击是 laterIndex=0
|
||||
if (!curComponent.value) {
|
||||
composeStore.setLaterIndex(null)
|
||||
}
|
||||
// ctrl or command 按下时 鼠标点击为选择需要组合的组件(取消需要组合的组件在ComposeShow组件中)
|
||||
if (isCtrlOrCmdDown.value && !areaData.value.components.includes(componentData.value[index])) {
|
||||
areaDataPush(componentData.value[index])
|
||||
if (curComponent.value && curComponent.value.id !== componentData.value[index].id) {
|
||||
areaDataPush(curComponent.value)
|
||||
}
|
||||
dvMainStore.setCurComponent({ component: null, index: null })
|
||||
e.stopPropagation()
|
||||
composeStore.setLaterIndex(index)
|
||||
return
|
||||
}
|
||||
//shift操作逻辑
|
||||
if (isShiftDown.value) {
|
||||
shiftDataPush(index)
|
||||
return
|
||||
}
|
||||
|
||||
//其他情况点击清理选择区域
|
||||
areaData.value.components.splice(0, areaData.value.components.length)
|
||||
setCurComponent(index)
|
||||
composeStore.setLaterIndex(index)
|
||||
}
|
||||
const deleteComponent = (number: number) => {
|
||||
setTimeout(() => {
|
||||
dvMainStore.deleteComponentById(curComponent.value.id)
|
||||
snapshotStore.recordSnapshotCache('renderChart')
|
||||
})
|
||||
}
|
||||
const upComponent = (number: number) => {
|
||||
setTimeout(() => {
|
||||
layerStore.upComponent()
|
||||
snapshotStore.recordSnapshotCache()
|
||||
})
|
||||
}
|
||||
const downComponent = (number: number) => {
|
||||
setTimeout(() => {
|
||||
layerStore.downComponent()
|
||||
snapshotStore.recordSnapshotCache('realTime-downComponent')
|
||||
})
|
||||
}
|
||||
const setCurComponent = index => {
|
||||
dvMainStore.setCurComponent({ component: componentData.value[index], index })
|
||||
}
|
||||
|
||||
let nameEdit = ref(false)
|
||||
let editComponentId = ref('')
|
||||
let inputName = ref('')
|
||||
let nameInput = ref(null)
|
||||
const editComponentName = item => {
|
||||
editComponentId.value = `#component-label-${item.id}`
|
||||
nameEdit.value = true
|
||||
inputName.value = item.name
|
||||
nextTick(() => {
|
||||
nameInput.value.focus()
|
||||
})
|
||||
}
|
||||
const closeEditComponentName = () => {
|
||||
nameEdit.value = false
|
||||
if (!inputName.value || !inputName.value.trim()) {
|
||||
return
|
||||
}
|
||||
if (inputName.value.trim() === curComponent.value.name) {
|
||||
return
|
||||
}
|
||||
curComponent.value.name = inputName.value
|
||||
inputName.value = ''
|
||||
}
|
||||
|
||||
const toggleComponentVisible = () => {
|
||||
// do toggleComponentVisible
|
||||
}
|
||||
|
||||
const lock = () => {
|
||||
setTimeout(() => {
|
||||
lockStore.lock()
|
||||
snapshotStore.recordSnapshotCache('realTime-lock')
|
||||
})
|
||||
}
|
||||
|
||||
const unlock = () => {
|
||||
setTimeout(() => {
|
||||
lockStore.unlock()
|
||||
snapshotStore.recordSnapshotCache('realTime-unlock')
|
||||
})
|
||||
}
|
||||
|
||||
const hideComponent = () => {
|
||||
setTimeout(() => {
|
||||
layerStore.hideComponent()
|
||||
snapshotStore.recordSnapshotCache('realTime-hideComponent')
|
||||
})
|
||||
}
|
||||
|
||||
const showComponent = () => {
|
||||
setTimeout(() => {
|
||||
layerStore.showComponent()
|
||||
snapshotStore.recordSnapshotCache()
|
||||
})
|
||||
}
|
||||
|
||||
const dragOnEnd = ({ oldIndex, newIndex }) => {
|
||||
const source = componentData.value[newIndex]
|
||||
const comLength = componentData.value.length
|
||||
// 还原数组
|
||||
componentData.value.splice(newIndex, 1)
|
||||
componentData.value.splice(oldIndex, 0, source)
|
||||
const target = componentData.value[comLength - 1 - oldIndex]
|
||||
// 反向移动数组
|
||||
componentData.value.splice(comLength - 1 - oldIndex, 1)
|
||||
componentData.value.splice(comLength - 1 - newIndex, 0, target)
|
||||
dvMainStore.setCurComponent({ component: target, index: transformIndex(comLength - oldIndex) })
|
||||
}
|
||||
|
||||
const getIconName = item => {
|
||||
if (item.component === 'UserView') {
|
||||
const viewInfo = canvasViewInfo.value[item.id]
|
||||
return `${viewInfo.type}-origin`
|
||||
} else {
|
||||
return item.icon
|
||||
}
|
||||
}
|
||||
|
||||
const menuAsideClose = (param, index) => {
|
||||
const iconDom = document.getElementById('close-button')
|
||||
if (iconDom) {
|
||||
iconDom.click()
|
||||
}
|
||||
if (param.opt === 'rename') {
|
||||
setTimeout(() => {
|
||||
editComponentName(getComponent(index))
|
||||
}, 200)
|
||||
}
|
||||
}
|
||||
const rename = item => {
|
||||
editComponentName(item)
|
||||
}
|
||||
|
||||
const handleContextMenu = e => {
|
||||
e.preventDefault()
|
||||
// 获取鼠标点击位置
|
||||
const x = e.clientX
|
||||
const y = e.clientY
|
||||
const customContextMenu = document.createElement('div')
|
||||
customContextMenu.style.position = 'fixed'
|
||||
customContextMenu.style.left = x + 'px'
|
||||
customContextMenu.style.top = y + 'px'
|
||||
|
||||
// 将自定义菜单添加到页面
|
||||
document.body.appendChild(customContextMenu)
|
||||
|
||||
// 为自定义菜单添加事件监听器,例如,点击菜单项后执行的操作
|
||||
customContextMenu.addEventListener('click', () => {
|
||||
// 在这里执行菜单项点击后的操作
|
||||
// 例如,关闭菜单
|
||||
document.body.removeChild(customContextMenu)
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!--为了保持图层视觉上的一致性 这里进行数组的倒序排列 相应的展示和移动按照倒序处理-->
|
||||
<div class="real-time-component-list">
|
||||
<button hidden="true" id="close-button"></button>
|
||||
<el-row class="list-wrap">
|
||||
<div class="list-container" @contextmenu="handleContextMenu">
|
||||
<draggable
|
||||
@end="dragOnEnd"
|
||||
:list="componentData"
|
||||
animation="100"
|
||||
class="drag-list"
|
||||
item-key="id"
|
||||
>
|
||||
<template #item="{ index }">
|
||||
<div
|
||||
:title="getComponent(index)?.name"
|
||||
class="component-item"
|
||||
:class="{
|
||||
'container-item-not-show': !getComponent(index)?.isShow,
|
||||
activated:
|
||||
(curComponent && curComponent?.id === getComponent(index)?.id) ||
|
||||
areaData.components.includes(getComponent(index))
|
||||
}"
|
||||
@click="onClick($event, transformIndex(index))"
|
||||
@dblclick="editComponentName(getComponent(index))"
|
||||
>
|
||||
<el-icon class="component-icon">
|
||||
<Icon :name="getIconName(getComponent(index))"></Icon>
|
||||
</el-icon>
|
||||
<span :id="`component-label-${getComponent(index)?.id}`" class="component-label">
|
||||
{{ getComponent(index)?.name }}
|
||||
</span>
|
||||
<div
|
||||
v-show="!nameEdit || (nameEdit && curComponent?.id !== getComponent(index)?.id)"
|
||||
class="icon-container"
|
||||
:class="{
|
||||
'icon-container-lock': getComponent(index)?.isLock && getComponent(index)?.isShow,
|
||||
'icon-container-show': !getComponent(index)?.isShow
|
||||
}"
|
||||
>
|
||||
<el-icon
|
||||
class="component-base component-icon-display"
|
||||
v-show="!getComponent(index).isShow"
|
||||
@click="showComponent"
|
||||
>
|
||||
<Icon name="dv-eye-close" class="opt-icon"></Icon>
|
||||
</el-icon>
|
||||
<el-icon
|
||||
class="component-base"
|
||||
v-show="getComponent(index)?.isShow"
|
||||
@click="hideComponent"
|
||||
>
|
||||
<Icon name="dv-show" class="opt-icon"></Icon>
|
||||
</el-icon>
|
||||
<el-icon v-show="!getComponent(index)?.isLock" class="component-base" @click="lock">
|
||||
<Icon class="opt-icon" name="dv-unlock"></Icon>
|
||||
</el-icon>
|
||||
<el-icon
|
||||
class="component-base component-icon-display"
|
||||
v-show="getComponent(index)?.isLock"
|
||||
@click="unlock"
|
||||
>
|
||||
<Icon name="dv-lock" class="opt-icon"></Icon>
|
||||
</el-icon>
|
||||
<el-dropdown
|
||||
ref="dropdownMore"
|
||||
trigger="click"
|
||||
placement="bottom-start"
|
||||
effect="dark"
|
||||
hide-timeout="0"
|
||||
>
|
||||
<span :class="'dropdownMore-' + index" @click="onClick(transformIndex(index))">
|
||||
<el-icon class="component-base">
|
||||
<Icon name="dv-more" class="opt-icon"></Icon>
|
||||
</el-icon>
|
||||
</span>
|
||||
<template #dropdown>
|
||||
<context-menu-aside-details
|
||||
:element="getComponent(index)"
|
||||
@close="menuAsideClose($event, index)"
|
||||
></context-menu-aside-details>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
<el-dropdown
|
||||
class="compose-dropdown"
|
||||
trigger="contextmenu"
|
||||
placement="bottom-start"
|
||||
effect="dark"
|
||||
hide-timeout="0"
|
||||
>
|
||||
<compose-show
|
||||
:show-border="false"
|
||||
:element-index="transformIndex(index)"
|
||||
:element="getComponent(index)"
|
||||
></compose-show>
|
||||
<template #dropdown>
|
||||
<context-menu-aside-details
|
||||
:element="getComponent(index)"
|
||||
@close="menuAsideClose($event, index)"
|
||||
></context-menu-aside-details>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</template>
|
||||
</draggable>
|
||||
<el-row style="width: 100%; height: 150px"></el-row>
|
||||
</div>
|
||||
</el-row>
|
||||
<Teleport v-if="editComponentId && nameEdit" :to="editComponentId">
|
||||
<input
|
||||
@keydown.stop
|
||||
@keyup.stop
|
||||
ref="nameInput"
|
||||
v-model="inputName"
|
||||
@blur="closeEditComponentName"
|
||||
/>
|
||||
</Teleport>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.real-time-component-list {
|
||||
white-space: nowrap;
|
||||
.list-wrap {
|
||||
max-height: calc(100% - @component-toolbar-height);
|
||||
overflow-y: auto;
|
||||
width: 100%;
|
||||
.list-container {
|
||||
width: 100%;
|
||||
.component-item {
|
||||
position: relative;
|
||||
height: 30px;
|
||||
width: 100%;
|
||||
cursor: grab;
|
||||
color: @dv-canvas-main-font-color;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
font-size: 12px;
|
||||
padding: 0 2px 0 22px;
|
||||
user-select: none;
|
||||
|
||||
.component-icon {
|
||||
color: #a6a6a6;
|
||||
font-size: 14px;
|
||||
}
|
||||
.component-label {
|
||||
color: #ebebeb;
|
||||
}
|
||||
|
||||
> span.component-label {
|
||||
font-size: 12px;
|
||||
margin-left: 10px;
|
||||
position: relative;
|
||||
min-width: 65px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
input {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
background-color: white;
|
||||
outline: none;
|
||||
border: none;
|
||||
border-radius: 2px;
|
||||
padding: 0 4px;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
&:active {
|
||||
cursor: grabbing;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(235, 235, 235, 0.1);
|
||||
|
||||
.icon-container {
|
||||
.component-base {
|
||||
opacity: 1;
|
||||
}
|
||||
width: 70px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.icon-container {
|
||||
.component-base {
|
||||
opacity: 0;
|
||||
}
|
||||
width: 0px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
flex-grow: 1;
|
||||
cursor: none;
|
||||
i {
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
.activated {
|
||||
background-color: rgba(51, 112, 255, 0.1) !important;
|
||||
:deep(.component-icon) {
|
||||
color: #3370ff;
|
||||
}
|
||||
:deep(.component-label) {
|
||||
color: #3370ff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.real-time-component-list :deep(.ed-popper) {
|
||||
background: #303133 !important;
|
||||
}
|
||||
|
||||
.component-base {
|
||||
cursor: pointer;
|
||||
height: 22px !important;
|
||||
width: 22px !important;
|
||||
border-radius: 4px;
|
||||
padding: 0 4px;
|
||||
|
||||
.opt-icon {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: rgba(235, 235, 235, 0.1);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background: rgba(235, 235, 235, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
.component-icon-display {
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
.icon-container-show {
|
||||
width: 70px !important;
|
||||
}
|
||||
|
||||
.icon-container-lock {
|
||||
width: 45px !important;
|
||||
}
|
||||
|
||||
.container-item-not-show {
|
||||
color: #5f5f5f !important;
|
||||
:deep(.component-icon) {
|
||||
color: #5f5f5f !important;
|
||||
}
|
||||
:deep(.component-label) {
|
||||
color: #5f5f5f !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="less">
|
||||
.compose-dropdown {
|
||||
position: initial !important;
|
||||
}
|
||||
</style>
|
@ -1,8 +1,9 @@
|
||||
package io.dataease.api.template;
|
||||
|
||||
import io.dataease.api.template.dto.TemplateManageDTO;
|
||||
import io.dataease.api.template.request.TemplateManageRequest;
|
||||
import io.dataease.api.template.vo.VisualizationTemplateVO;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface TemplateManageApi {
|
||||
@ -10,4 +11,19 @@ public interface TemplateManageApi {
|
||||
@PostMapping("/templateList")
|
||||
List<TemplateManageDTO> templateList();
|
||||
|
||||
@PostMapping("/save")
|
||||
TemplateManageDTO save(@RequestBody TemplateManageRequest request);
|
||||
|
||||
@DeleteMapping("/delete/{id}")
|
||||
void delete(@PathVariable String id);
|
||||
|
||||
@GetMapping("/findOne/{id}")
|
||||
VisualizationTemplateVO findOne(@PathVariable String id) throws Exception;
|
||||
|
||||
@PostMapping("/find")
|
||||
List<TemplateManageDTO> find(@RequestBody TemplateManageRequest request);
|
||||
|
||||
@PostMapping("/nameCheck")
|
||||
String nameCheck(@RequestBody TemplateManageRequest request);
|
||||
|
||||
}
|
||||
|
@ -1,15 +1,20 @@
|
||||
package io.dataease.api.template.dto;
|
||||
|
||||
|
||||
import io.dataease.api.template.vo.VisualizationTemplateVO;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@Data
|
||||
public class TemplateManageDTO {
|
||||
public class TemplateManageDTO extends VisualizationTemplateVO {
|
||||
|
||||
private String label;
|
||||
|
||||
private Integer childrenCount;
|
||||
|
||||
private List<TemplateManageDTO> children;
|
||||
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,29 @@
|
||||
package io.dataease.api.template.request;
|
||||
|
||||
import io.dataease.api.template.vo.VisualizationTemplateVO;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* Author: wangjiahao
|
||||
* Date: 2021-03-05
|
||||
* Description:
|
||||
*/
|
||||
@Data
|
||||
public class TemplateManageRequest extends VisualizationTemplateVO {
|
||||
private String sort;
|
||||
private String withBlobs="N";
|
||||
|
||||
private String optType;
|
||||
|
||||
private String staticResource;
|
||||
|
||||
private Boolean withChildren = false;
|
||||
|
||||
public TemplateManageRequest() {
|
||||
}
|
||||
|
||||
public TemplateManageRequest(String pid) {
|
||||
super.setPid(pid);
|
||||
withBlobs="N";
|
||||
}
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
package io.dataease.api.template.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author : WangJiaHao
|
||||
* @date : 2023/11/7 13:22
|
||||
*/
|
||||
@Data
|
||||
public class VisualizationTemplateVO {
|
||||
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* 名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 父级id
|
||||
*/
|
||||
private String pid;
|
||||
|
||||
/**
|
||||
* 层级
|
||||
*/
|
||||
private Integer level;
|
||||
|
||||
/**
|
||||
* 模版种类 dataV or dashboard 目录或者文件夹
|
||||
*/
|
||||
private String dvType;
|
||||
|
||||
/**
|
||||
* 节点类型 folder or panel 目录或者文件夹
|
||||
*/
|
||||
private String nodeType;
|
||||
|
||||
/**
|
||||
* 创建人
|
||||
*/
|
||||
private String createBy;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private Long createTime;
|
||||
|
||||
/**
|
||||
* 缩略图
|
||||
*/
|
||||
private String snapshot;
|
||||
|
||||
/**
|
||||
* 模版类型 system 系统内置 self 用户自建
|
||||
*/
|
||||
private String templateType;
|
||||
|
||||
/**
|
||||
* template 样式
|
||||
*/
|
||||
private String templateStyle;
|
||||
|
||||
/**
|
||||
* template 数据
|
||||
*/
|
||||
private String templateData;
|
||||
|
||||
/**
|
||||
* 预存数据
|
||||
*/
|
||||
private String dynamicData;
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
package io.dataease.constant;
|
||||
|
||||
/**
|
||||
* Author: wangjiahao
|
||||
* Description:
|
||||
*/
|
||||
public class CommonConstants {
|
||||
|
||||
|
||||
//操作类型
|
||||
public static final class OPT_TYPE {
|
||||
|
||||
public static final String INSERT = "insert";
|
||||
|
||||
public static final String UPDATE = "update";
|
||||
|
||||
public static final String DELETE = "delete";
|
||||
|
||||
public static final String SELECT = "select";
|
||||
|
||||
}
|
||||
|
||||
//操作类型
|
||||
public static final class CHECK_RESULT {
|
||||
|
||||
// 不存在
|
||||
public static final String NONE = "none";
|
||||
|
||||
// 全局存在
|
||||
public static final String EXIST_ALL = "exist_all";
|
||||
|
||||
// 当前用户存在
|
||||
public static final String EXIST_USER = "exist_user";
|
||||
|
||||
// 其他用户存在
|
||||
public static final String EXIST_OTHER = "exist_other";
|
||||
|
||||
}
|
||||
|
||||
//视图数据查询来源
|
||||
public static final class VIEW_QUERY_FROM {
|
||||
|
||||
// 仪表板
|
||||
public static final String PANEL = "panel";
|
||||
|
||||
// 仪表板编辑
|
||||
public static final String PANEL_EDIT = "panel_edit";
|
||||
|
||||
}
|
||||
|
||||
//视图数据查询模式
|
||||
public static final class VIEW_RESULT_MODE {
|
||||
|
||||
// 所有
|
||||
public static final String ALL = "all";
|
||||
|
||||
// 自定义
|
||||
public static final String CUSTOM = "custom";
|
||||
}
|
||||
|
||||
//视图数据查询来源
|
||||
public static final class VIEW_EDIT_FROM {
|
||||
|
||||
// 仪表板
|
||||
public static final String PANEL = "panel";
|
||||
|
||||
// 仪表板编辑
|
||||
public static final String CACHE = "cache";
|
||||
|
||||
}
|
||||
|
||||
//视图数据读取来源
|
||||
public static final class VIEW_DATA_FROM {
|
||||
|
||||
// 模板数据
|
||||
public static final String TEMPLATE = "template";
|
||||
|
||||
//数据集数据
|
||||
public static final String CHART = "dataset";
|
||||
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user