feat(数据大屏): 大屏的tab组件支持图表组合后拖进去

This commit is contained in:
wangjiahao
2024-12-17 18:59:27 +08:00
committed by 王嘉豪
parent cccea9878c
commit 1fde5fabe8
7 changed files with 195 additions and 99 deletions

View File

@@ -61,6 +61,8 @@ import dvShow from '@/assets/svg/dv-show.svg'
import dvUnlock from '@/assets/svg/dv-unlock.svg'
import dvLock from '@/assets/svg/dv-lock.svg'
import dvMore from '@/assets/svg/dv-more.svg'
import dvExpandDown from '@/assets/svg/dv-expand-down.svg'
import dvExpandRight from '@/assets/svg/dv-expand-right.svg'
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
import { snapshotStoreWithOut } from '@/store/modules/data-visualization/snapshot'
import { layerStoreWithOut } from '@/store/modules/data-visualization/layer'
@@ -74,6 +76,7 @@ import ContextMenuAsideDetails from '@/components/data-visualization/canvas/Cont
import ComposeShow from '@/components/data-visualization/canvas/ComposeShow.vue'
import { composeStoreWithOut } from '@/store/modules/data-visualization/compose'
import circlePackingOrigin from '@/assets/svg/circle-packing-origin.svg'
import RealTimeTab from '@/components/data-visualization/RealTimeTab.vue'
const dropdownMore = ref(null)
const lockStore = lockStoreWithOut()
@@ -278,6 +281,9 @@ const handleContextMenu = e => {
document.body.removeChild(customContextMenu)
})
}
const expandClick = component => {
component['expand'] = !component['expand']
}
</script>
<template>
@@ -294,71 +300,116 @@ const handleContextMenu = e => {
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(transformIndex(index))"
>
<el-icon class="component-icon">
<Icon><component :is="getIconName(getComponent(index))"></component></Icon>
</el-icon>
<span
:id="`component-label-${getComponent(index)?.id}`"
class="component-label"
@dblclick="editComponentName(getComponent(index))"
>
{{ getComponent(index)?.name }}
</span>
<div>
<div
v-show="!nameEdit || (nameEdit && curComponent?.id !== getComponent(index)?.id)"
class="icon-container"
:title="getComponent(index)?.name"
class="component-item"
:class="{
'icon-container-lock': getComponent(index)?.isLock && getComponent(index)?.isShow,
'icon-container-show': !getComponent(index)?.isShow
'container-item-not-show': !getComponent(index)?.isShow,
activated:
(curComponent && curComponent?.id === getComponent(index)?.id) ||
areaData.components.includes(getComponent(index))
}"
@click="onClick(transformIndex(index))"
>
<el-icon
class="component-base component-icon-display"
v-show="!getComponent(index).isShow"
@click="showComponent"
<div
v-show="['DeTabs'].includes(getComponent(index)?.component)"
style="width: 22px; padding-left: 3px"
>
<Icon name="dv-eye-close"><dvEyeClose class="svg-icon opt-icon" /></Icon>
<el-icon class="component-expand" @click="expandClick(getComponent(index))">
<Icon
v-if="getComponent(index)?.expand"
name="dv-expand-down"
class="expand-icon"
><dvExpandDown class="svg-icon expand-icon"
/></Icon>
<Icon
v-if="!getComponent(index)?.expand"
name="dv-expand-right"
class="expand-icon"
><dvExpandRight class="svg-icon expand-icon"
/></Icon>
</el-icon>
</div>
<el-icon class="component-icon">
<Icon><component :is="getIconName(getComponent(index))"></component></Icon>
</el-icon>
<el-icon
class="component-base"
v-show="getComponent(index)?.isShow"
@click="hideComponent"
<span
:id="`component-label-${getComponent(index)?.id}`"
class="component-label"
@dblclick="editComponentName(getComponent(index))"
>
<Icon name="dv-show"><dvShow class="svg-icon opt-icon" /></Icon>
</el-icon>
<el-icon v-show="!getComponent(index)?.isLock" class="component-base" @click="lock">
<Icon name="dv-unlock"><dvUnlock class="svg-icon opt-icon" /></Icon>
</el-icon>
<el-icon
class="component-base component-icon-display"
v-show="getComponent(index)?.isLock"
@click="unlock"
{{ 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
}"
>
<Icon name="dv-lock"><dvLock class="svg-icon opt-icon" /></Icon>
</el-icon>
<el-icon
class="component-base component-icon-display"
v-show="!getComponent(index).isShow"
@click="showComponent"
>
<Icon name="dv-eye-close"><dvEyeClose class="svg-icon opt-icon" /></Icon>
</el-icon>
<el-icon
class="component-base"
v-show="getComponent(index)?.isShow"
@click="hideComponent"
>
<Icon name="dv-show"><dvShow class="svg-icon opt-icon" /></Icon>
</el-icon>
<el-icon
v-show="!getComponent(index)?.isLock"
class="component-base"
@click="lock"
>
<Icon name="dv-unlock"><dvUnlock class="svg-icon opt-icon" /></Icon>
</el-icon>
<el-icon
class="component-base component-icon-display"
v-show="getComponent(index)?.isLock"
@click="unlock"
>
<Icon name="dv-lock"><dvLock class="svg-icon 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"><dvMore class="svg-icon 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
ref="dropdownMore"
trigger="click"
class="compose-dropdown"
trigger="contextmenu"
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"><dvMore class="svg-icon opt-icon" /></Icon>
</el-icon>
</span>
<compose-show
:show-border="false"
:element-index="transformIndex(index)"
:element="getComponent(index)"
></compose-show>
<template #dropdown>
<context-menu-aside-details
:element="getComponent(index)"
@@ -367,25 +418,15 @@ const handleContextMenu = e => {
</template>
</el-dropdown>
</div>
<el-dropdown
class="compose-dropdown"
trigger="contextmenu"
placement="bottom-start"
effect="dark"
:hide-timeout="0"
<div
v-if="getComponent(index)?.component === 'DeTabs' && getComponent(index)?.expand"
>
<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>
<real-time-tab
:tab-element="getComponent(index)"
tab-position="groupTab"
:component-data="getComponent(index).propValue"
></real-time-tab>
</div>
</div>
</template>
</draggable>
@@ -423,7 +464,7 @@ const handleContextMenu = e => {
align-items: center;
justify-content: flex-start;
font-size: 12px;
padding: 0 2px 0 44px;
padding: 0 2px 0 20px;
user-select: none;
.component-icon {

View File

@@ -507,12 +507,11 @@ const canvasChange = () => {
}"
@click="onClick($event, transformIndex(index))"
>
<div style="width: 22px; padding-left: 3px">
<el-icon
v-show="['Group', 'DeTabs'].includes(getComponent(index)?.component)"
class="component-expand"
@click="expandClick(getComponent(index))"
>
<div
v-show="['Group', 'DeTabs'].includes(getComponent(index)?.component)"
style="width: 22px; padding-left: 3px"
>
<el-icon class="component-expand" @click="expandClick(getComponent(index))">
<Icon
v-if="getComponent(index)?.expand"
name="dv-expand-down"

View File

@@ -22,6 +22,11 @@ const { areaData } = storeToRefs(composeStore)
const { curTabName } = storeToRefs(dvMainStore)
const props = defineProps({
tabPosition: {
type: String,
required: false,
default: 'main'
},
componentData: [],
tabElement: {}
})
@@ -31,10 +36,6 @@ const { componentData, tabElement } = toRefs(props)
const getComponent = index => {
return componentData.value[index]
}
const transformIndex = index => {
return componentData.value.length - 1 - index
}
const onClick = item => {
if (item) {
dvMainStore.setCurTabName(item.name)
@@ -136,7 +137,8 @@ const expandClick = component => {
:title="getComponent(index)?.title"
class="component-item"
:class="{
activated: curTabName === getComponent(index)?.name
activated: curTabName === getComponent(index)?.name,
'component-item-group': props.tabPosition === 'groupTab'
}"
@click="onClick(getComponent(index))"
>
@@ -191,6 +193,9 @@ const expandClick = component => {
</template>
<style lang="less" scoped>
.component-item-group {
padding: 0 2px 0 40px !important;
}
.real-time-component-list {
white-space: nowrap;
.list-wrap {

View File

@@ -201,6 +201,7 @@ const {
themes
} = toRefs(props)
const mainCanvasFlag = isMainCanvas(canvasId.value)
const editorX = ref(0)
const editorY = ref(0)
const start = ref({
@@ -1605,11 +1606,12 @@ defineExpose({
:class="{ lock: item.isLock && editMode === 'edit' }"
:base-cell-info="baseCellInfo"
:canvas-active="canvasActive"
:is-tab-move-check="mainCanvasFlag"
@onStartResize="onStartResize($event, item, index)"
@onStartMove="onStartMove($event, item, index)"
@onMouseUp="onMouseUp($event, item, index)"
@onDragging="onDragging($event, item, index)"
@onResizing="onResizing($event, item, index)"
@onMouseUp="onMouseUp($event)"
@onDragging="onDragging($event, item)"
@onResizing="onResizing($event, item)"
@userViewEnlargeOpen="userViewEnlargeOpen($event, item)"
@datasetParamsInit="datasetParamsInit(item)"
@linkJumpSetOpen="linkJumpSetOpen(item)"

View File

@@ -131,13 +131,14 @@ import Icon from '@/components/icon-custom/src/Icon.vue'
import ComponentEditBar from '@/components/visualization/ComponentEditBar.vue'
import { useEmitt } from '@/hooks/web/useEmitt'
import ComposeShow from '@/components/data-visualization/canvas/ComposeShow.vue'
import { groupSizeStyleAdaptor, groupStyleRevert, tabInnerStyleRevert } from '@/utils/style'
import {
groupSizeStyleAdaptor,
groupStyleRevert,
groupStyleRevertBatch,
tabInnerStyleRevert
} from '@/utils/style'
import { isDashboard, isGroupCanvas, isMainCanvas, isTabCanvas } from '@/utils/canvasUtils'
isDashboard,
isGroupCanvas,
isMainCanvas,
isTabCanvas,
itemCanvasPathCheck
} from '@/utils/canvasUtils'
import Board from '@/components/de-board/Board.vue'
import { activeWatermarkCheckUser, removeActiveWatermark } from '@/components/watermark/watermark'
const dvMainStore = dvMainStoreWithOut()
@@ -193,7 +194,6 @@ const state = reactive({
})
const contentDisplay = ref(true)
const shapeLock = computed(() => {
return element.value['isLock'] && isEditMode.value
})
@@ -282,6 +282,8 @@ const {
scale,
canvasActive
} = toRefs(props)
let pTabGroupFlag = itemCanvasPathCheck(element.value, 'pTabGroup')
const domId = ref('shape-id-' + element.value.id)
const pointList = ['lt', 't', 'rt', 'r', 'rb', 'b', 'lb', 'l']
const pointCorner = ['lt', 'rt', 'rb', 'lb']
@@ -459,7 +461,7 @@ const areaDataPush = component => {
!component.isLock &&
component.isShow &&
component.canvasId === 'canvas-main' &&
!['GroupArea', 'DeTabs'].includes(component.component)
!['GroupArea'].includes(component.component)
) {
areaData.value.components.push(component)
}
@@ -550,7 +552,9 @@ const handleMouseDownOnShape = e => {
// 非主画布非分组画布的情况 需要检测是否从Tab中移除组件(向左移除30px 或者向右移除30px 向左移除30px)
// 因为仪表板中组件向下移动可能只是为了挤占空间 不一定是为了移出 这里无法判断明确意图 暂时支不支持向下移出
// 大屏和仪表板暂时做位置算法区分 仪表板暂时使用curX 因为缩放的影响 大屏使用 tab位置 + 组件位置(相对内部画布)+初始触发点
// 如果组件再tab中且tab在Group中 不允许移入移出 pTabGroupFlag = true
if (
!pTabGroupFlag &&
!isMainCanvas(canvasId.value) &&
!isGroupCanvas(canvasId.value) &&
!isGroupArea.value &&
@@ -797,7 +801,6 @@ const handleMouseDownOnPoint = (point, e) => {
const up = () => {
// 如果内部组件保持尺寸时,这里在鼠标抬起时,重新计算一下内部组件占比
if (['DeTabs'].includes(element.value.component) && element.value.resizeInnerKeep) {
console.log('===test3==')
tabInnerStyleRevert(element.value)
}

View File

@@ -9,7 +9,7 @@ import {
commonAttr,
COMMON_COMPONENT_BACKGROUND_MAP
} from '@/custom-component/component-list'
import { createGroupStyle, getComponentRotatedStyle, groupStyleRevert } from '@/utils/style'
import { createGroupStyle, getComponentRotatedStyle } from '@/utils/style'
import eventBus from '@/utils/eventBus'
const dvMainStore = dvMainStoreWithOut()
@@ -46,7 +46,6 @@ export const composeStore = defineStore('compose', {
},
setSpaceDownStatus(value) {
this.isSpaceDown = value
console.log('====isSpaceDown=' + this.isSpaceDown)
},
setIsCtrlOrCmdDownStatus(value) {
this.isCtrlOrCmdDown = value
@@ -158,7 +157,7 @@ export const composeStore = defineStore('compose', {
})
components.push(...component.propValue)
} else if (['DeTabs', 'GroupArea'].includes(component.component)) {
} else if (['GroupArea'].includes(component.component)) {
// do nothing GroupAreas组合视阔区 DeTabs 均不加入分组中
} else {
components.push(component)
@@ -209,7 +208,7 @@ export const composeStore = defineStore('compose', {
// 将已经放到 Group 组件数据删除,也就是在 componentData 中删除,因为它们已经从 componentData 挪到 Group 组件中了
batchDeleteComponent(deleteData) {
deleteData.forEach(component => {
if (!['DeTabs', 'GroupArea'].includes(component.component)) {
if (!['GroupArea'].includes(component.component)) {
for (let i = 0, len = componentData.value.length; i < len; i++) {
if (component.id == componentData.value[i].id) {
componentData.value.splice(i, 1)

View File

@@ -1,4 +1,4 @@
import { cloneDeep } from 'lodash-es'
import { cloneDeep, forEach } from 'lodash-es'
import componentList, {
ACTION_SELECTION,
BASE_CAROUSEL,
@@ -633,6 +633,53 @@ export function isMainCanvas(canvasId) {
return canvasId === 'canvas-main'
}
// 目前仅允许group中还有一层Tab 或者 Tab中含有一层group
export function itemCanvasPathCheck(item, checkType) {
console.log('===test==' + item.component + '==' + checkType)
if (checkType === 'canvas-main') {
return isMainCanvas(item.canvasId)
}
const pathMap = {}
componentData.value.forEach(componentItem => {
canvasIdMapCheck(componentItem, null, pathMap)
})
// 父组件是Tab且否在group中
if (checkType === 'pTabGroup') {
return Boolean(
pathMap[item.id] &&
pathMap[item.id].component === 'DeTabs' &&
pathMap[pathMap[item.id].id] &&
pathMap[pathMap[item.id].id].component === 'Group'
)
}
// 父组件是group且否在Tab中
if (checkType === 'pGroupTab') {
return Boolean(
pathMap[item.id] &&
pathMap[item.id].component === 'Group' &&
pathMap[pathMap[item.id].id] &&
pathMap[pathMap[item.id].id].component === 'DeTabs'
)
}
return false
}
export function canvasIdMapCheck(item, pItem, pathMap) {
pathMap[item.id] = pItem
if (item.component === 'DeTabs') {
item.propValue.forEach(tabItem => {
tabItem.componentData.forEach(tabComponent => {
canvasIdMapCheck(tabComponent, item, pathMap)
})
})
} else if (item.component === 'Group') {
item.propValue.forEach(groupItem => {
canvasIdMapCheck(groupItem, item, pathMap)
})
}
}
export function isSameCanvas(item, canvasId) {
return item.canvasId === canvasId
}