mirror of
https://github.com/dataease/dataease.git
synced 2026-05-14 21:12:33 +08:00
feat(数据大屏): 大屏的tab组件支持图表组合后拖进去
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)"
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user