forked from github/dataease
feat(数据大屏): 鼠标选中一些区域后,区域内的组件可通过滑动鼠标,批量移动
This commit is contained in:
parent
18c78379bd
commit
18bd0695b9
@ -221,6 +221,7 @@ const handleContextMenu = e => {
|
||||
<template #item="{ index }">
|
||||
<div>
|
||||
<div
|
||||
v-show="getComponent(index)?.component !== 'GroupArea'"
|
||||
:title="getComponent(index)?.name"
|
||||
class="component-item"
|
||||
:class="{
|
||||
|
@ -9,7 +9,7 @@ import {
|
||||
syncShapeItemStyle
|
||||
} from '@/utils/style'
|
||||
import $ from 'jquery'
|
||||
import { _$, isPreventDrop } from '@/utils/utils'
|
||||
import { _$, deepCopy, isPreventDrop } from '@/utils/utils'
|
||||
import ContextMenu from './ContextMenu.vue'
|
||||
import MarkLine from './MarkLine.vue'
|
||||
import Area from './Area.vue'
|
||||
@ -26,6 +26,7 @@ import DragShadow from '@/components/data-visualization/canvas/DragShadow.vue'
|
||||
import {
|
||||
canvasSave,
|
||||
findDragComponent,
|
||||
findNewComponent,
|
||||
isGroupCanvas,
|
||||
isMainCanvas,
|
||||
isSameCanvas
|
||||
@ -396,6 +397,7 @@ const hideArea = () => {
|
||||
},
|
||||
components: []
|
||||
})
|
||||
groupAreaChange(false)
|
||||
}
|
||||
|
||||
const createGroup = () => {
|
||||
@ -442,19 +444,23 @@ const createGroup = () => {
|
||||
width.value = right - left
|
||||
height.value = bottom - top
|
||||
|
||||
const areaDataStyle = {
|
||||
left,
|
||||
top,
|
||||
width: width.value,
|
||||
height: height.value
|
||||
}
|
||||
|
||||
// 设置选中区域位移大小信息和区域内的组件数据
|
||||
composeStore.setAreaData({
|
||||
style: {
|
||||
left,
|
||||
top,
|
||||
width: width.value,
|
||||
height: height.value
|
||||
},
|
||||
style: areaDataStyle,
|
||||
components: areaData
|
||||
})
|
||||
// 如果有组件被group选中 取消当前画布选中的组件
|
||||
if (areaData.length > 0) {
|
||||
dvMainStore.setCurComponent({ component: null, index: null })
|
||||
isShowArea.value = false
|
||||
groupAreaChange(true, areaDataStyle)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1346,6 +1352,21 @@ const contextMenuShow = computed(() => {
|
||||
|
||||
const markLineShow = computed(() => isMainCanvas(canvasId.value))
|
||||
|
||||
const groupAreaChange = (showArea, style?) => {
|
||||
nextTick(() => {
|
||||
if (showArea) {
|
||||
const groupArea = findNewComponent('GroupArea', 'GroupArea')
|
||||
groupArea.style.left = style.left
|
||||
groupArea.style.top = style.top
|
||||
groupArea.style.width = style.width
|
||||
groupArea.style.height = style.height
|
||||
dvMainStore.addComponent({ component: groupArea, index: undefined })
|
||||
} else {
|
||||
dvMainStore.deleteComponentById(100000001)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (isMainCanvas(canvasId.value)) {
|
||||
initSnapshotTimer()
|
||||
|
@ -1,5 +1,11 @@
|
||||
<template>
|
||||
<div class="shape" ref="shapeInnerRef" :id="domId" @dblclick="handleDbClick">
|
||||
<div
|
||||
class="shape"
|
||||
:class="{ 'shape-group-area': isGroupArea }"
|
||||
ref="shapeInnerRef"
|
||||
:id="domId"
|
||||
@dblclick="handleDbClick"
|
||||
>
|
||||
<div v-if="showCheck" class="del-from-mobile" @click="delFromMobile">
|
||||
<el-icon>
|
||||
<Icon name="mobile-checkbox"></Icon>
|
||||
@ -49,6 +55,7 @@
|
||||
</div>
|
||||
<div
|
||||
v-for="item in isActive() ? getPointList() : []"
|
||||
v-show="!isGroupArea"
|
||||
:key="item"
|
||||
class="shape-point"
|
||||
:style="getPointStyle(item)"
|
||||
@ -280,6 +287,10 @@ const angleToCursor = [
|
||||
{ start: 293, end: 338, cursor: 'w' }
|
||||
]
|
||||
|
||||
const isGroupArea = computed(() => {
|
||||
return curComponent.value?.component === 'GroupArea'
|
||||
})
|
||||
|
||||
const active = computed(() => {
|
||||
return curComponent.value?.id === element.value.id
|
||||
})
|
||||
@ -518,16 +529,19 @@ const handleMouseDownOnShape = e => {
|
||||
isFirst = false
|
||||
}
|
||||
// 修改当前组件样式
|
||||
dvMainStore.setShapeStyle(pos)
|
||||
dvMainStore.setShapeStyle(pos, areaData.value.components)
|
||||
// 等更新完当前组件的样式并绘制到屏幕后再判断是否需要吸附
|
||||
// 如果不使用 $nextTick,吸附后将无法移动
|
||||
nextTick(() => {
|
||||
// 触发元素移动事件,用于显示标线、吸附功能
|
||||
// 后面两个参数代表鼠标移动方向
|
||||
// curY - startY > 0 true 表示向下移动 false 表示向上移动
|
||||
// curX - startX > 0 true 表示向右移动 false 表示向左移动
|
||||
eventBus.emit('move', { isDownward: curY - startY > 0, isRightward: curX - startX > 0 })
|
||||
})
|
||||
// GroupArea是分组视括租金 不需要进行吸附
|
||||
// 如果不使用 nextTick,吸附后将无法移动
|
||||
if (!isGroupArea.value) {
|
||||
nextTick(() => {
|
||||
// 触发元素移动事件,用于显示标线、吸附功能
|
||||
// 后面两个参数代表鼠标移动方向
|
||||
// curY - startY > 0 true 表示向下移动 false 表示向上移动
|
||||
// curX - startX > 0 true 表示向右移动 false 表示向左移动
|
||||
eventBus.emit('move', { isDownward: curY - startY > 0, isRightward: curX - startX > 0 })
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const up = () => {
|
||||
@ -754,7 +768,7 @@ const commonBackgroundSvgInner = computed(() => {
|
||||
})
|
||||
|
||||
const componentBackgroundStyle = computed(() => {
|
||||
if (element.value.commonBackground) {
|
||||
if (element.value.commonBackground && element.value.component !== 'GroupArea') {
|
||||
const {
|
||||
backgroundColorSelect,
|
||||
backgroundColor,
|
||||
@ -937,6 +951,10 @@ onMounted(() => {
|
||||
}
|
||||
}
|
||||
|
||||
.shape-group-area {
|
||||
z-index: 15;
|
||||
}
|
||||
|
||||
.shape-shadow {
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
@ -78,6 +78,19 @@ export const commonAttr = {
|
||||
|
||||
// 编辑器左侧组件列表
|
||||
const list = [
|
||||
{
|
||||
id: 100000001,
|
||||
component: 'GroupArea',
|
||||
name: '组合区域',
|
||||
label: '组合区域',
|
||||
propValue: ' ',
|
||||
icon: 'icon_graphical',
|
||||
innerType: 'GroupArea',
|
||||
style: {
|
||||
width: 200,
|
||||
height: 200
|
||||
}
|
||||
},
|
||||
{
|
||||
component: 'VQuery',
|
||||
name: '查询',
|
||||
|
13
core/core-frontend/src/custom-component/group-area/Attr.vue
Normal file
13
core/core-frontend/src/custom-component/group-area/Attr.vue
Normal file
@ -0,0 +1,13 @@
|
||||
<template>
|
||||
<div class="attr-list de-collapse-style">
|
||||
<CommonAttr :element="curComponent"></CommonAttr>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
|
||||
import CommonAttr from '@/custom-component/common/CommonAttr.vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
const dvMainStore = dvMainStoreWithOut()
|
||||
const { curComponent } = storeToRefs(dvMainStore)
|
||||
</script>
|
@ -0,0 +1,13 @@
|
||||
<template>
|
||||
<div class="area"></div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts"></script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.area {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 1px solid #70c0ff;
|
||||
}
|
||||
</style>
|
@ -254,7 +254,19 @@ export const dvMainStore = defineStore('dataVisualization', {
|
||||
this.bashMatrixInfo = bashMatrixInfo
|
||||
},
|
||||
|
||||
setShapeStyle({ top, left, width, height, rotate }) {
|
||||
setShapeStyle({ top, left, width, height, rotate }, areaDataComponents = []) {
|
||||
if (this.curComponent.component === 'GroupArea' && areaDataComponents.length > 0) {
|
||||
const topOffset = top - this.curComponent.style.top
|
||||
const leftOffset = left - this.curComponent.style.left
|
||||
const widthOffset = width - this.curComponent.style.width
|
||||
const heightOffset = height - this.curComponent.style.height
|
||||
areaDataComponents.forEach(component => {
|
||||
component.style.top = component.style.top + topOffset
|
||||
component.style.left = component.style.left + leftOffset
|
||||
component.style.width = component.style.width + widthOffset
|
||||
component.style.height = component.style.height + heightOffset
|
||||
})
|
||||
}
|
||||
if (this.dvInfo.type === 'dashboard') {
|
||||
if (top) this.curComponent.style.top = top < 0 ? 0 : Math.round(top)
|
||||
if (left) this.curComponent.style.left = left < 0 ? 0 : Math.round(left)
|
||||
|
@ -23,6 +23,8 @@ import SvgTriangle from '@/custom-component/svgs/svg-triangle/Component.vue'
|
||||
import SvgTriangleAttr from '@/custom-component/svgs/svg-triangle/Attr.vue'
|
||||
import DeTimeClock from '@/custom-component/de-time-clock/Component.vue'
|
||||
import DeTimeClockAttr from '@/custom-component/de-time-clock/Attr.vue'
|
||||
import GroupArea from '@/custom-component/group-area/Component.vue'
|
||||
import GroupAreaAttr from '@/custom-component/group-area/Attr.vue'
|
||||
export const componentsMap = {
|
||||
VText: VText,
|
||||
VQuery,
|
||||
@ -48,7 +50,9 @@ export const componentsMap = {
|
||||
SvgTriangle: SvgTriangle,
|
||||
SvgTriangleAttr: SvgTriangleAttr,
|
||||
DeTimeClock: DeTimeClock,
|
||||
DeTimeClockAttr: DeTimeClockAttr
|
||||
DeTimeClockAttr: DeTimeClockAttr,
|
||||
GroupArea: GroupArea,
|
||||
GroupAreaAttr: GroupAreaAttr
|
||||
}
|
||||
|
||||
export default function findComponent(key) {
|
||||
|
@ -279,6 +279,15 @@ onUnmounted(() => {
|
||||
|
||||
const previewStatus = computed(() => editMode.value === 'preview')
|
||||
|
||||
const commonPropertiesShow = computed(
|
||||
() => curComponent.value && !['UserView', 'GroupArea'].includes(curComponent.value.component)
|
||||
)
|
||||
const canvasPropertiesShow = computed(
|
||||
() => !curComponent.value || ['GroupArea'].includes(curComponent.value.component)
|
||||
)
|
||||
const viewsPropertiesShow = computed(
|
||||
() => curComponent.value && ['UserView'].includes(curComponent.value.component)
|
||||
)
|
||||
eventBus.on('handleNew', handleNew)
|
||||
</script>
|
||||
|
||||
@ -331,7 +340,7 @@ eventBus.on('handleNew', handleNew)
|
||||
<!-- 右侧侧组件列表 -->
|
||||
<div style="width: auto; height: 100%" ref="leftSidebarRef">
|
||||
<dv-sidebar
|
||||
v-if="curComponent && !['UserView'].includes(curComponent.component)"
|
||||
v-if="commonPropertiesShow"
|
||||
:title="'属性'"
|
||||
:width="240"
|
||||
:side-name="'componentProp'"
|
||||
@ -342,7 +351,7 @@ eventBus.on('handleNew', handleNew)
|
||||
<component :is="findComponent(curComponent['component'] + 'Attr')" />
|
||||
</dv-sidebar>
|
||||
<dv-sidebar
|
||||
v-show="!curComponent"
|
||||
v-show="canvasPropertiesShow"
|
||||
:title="'大屏配置'"
|
||||
:width="240"
|
||||
:side-name="'canvas'"
|
||||
@ -353,7 +362,7 @@ eventBus.on('handleNew', handleNew)
|
||||
<canvas-attr></canvas-attr>
|
||||
</dv-sidebar>
|
||||
<editor
|
||||
v-show="curComponent && ['UserView'].includes(curComponent.component)"
|
||||
v-show="viewsPropertiesShow"
|
||||
:view="canvasViewInfo[curComponent ? curComponent.id : 'default']"
|
||||
themes="dark"
|
||||
:dataset-tree="state.datasetTree"
|
||||
|
Loading…
Reference in New Issue
Block a user