mirror of
https://github.com/dataease/dataease.git
synced 2025-02-24 11:32:57 +08:00
refactor(数据大屏): 优化分组Tab嵌套
This commit is contained in:
parent
b72be2c56e
commit
0dbe7738d1
@ -77,6 +77,7 @@ 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'
|
||||
import RealTimeGroupInner from '@/components/data-visualization/RealTimeGroupInner.vue'
|
||||
const dropdownMore = ref(null)
|
||||
const lockStore = lockStoreWithOut()
|
||||
|
||||
@ -319,8 +320,8 @@ const expandClick = component => {
|
||||
@click="onClick(transformIndex(index))"
|
||||
>
|
||||
<div
|
||||
v-show="['DeTabs'].includes(getComponent(index)?.component)"
|
||||
style="width: 22px"
|
||||
v-if="['DeTabs', 'Group'].includes(getComponent(index)?.component)"
|
||||
style="width: 12px; margin-right: 10px"
|
||||
>
|
||||
<el-icon class="component-expand" @click="expandClick(getComponent(index))">
|
||||
<Icon
|
||||
@ -433,6 +434,12 @@ const expandClick = component => {
|
||||
:component-data="getComponent(index).propValue"
|
||||
></real-time-tab>
|
||||
</div>
|
||||
<div v-if="getComponent(index)?.component === 'Group' && getComponent(index)?.expand">
|
||||
<real-time-group-inner
|
||||
tab-position="groupTab"
|
||||
:component-data="getComponent(index).componentData"
|
||||
></real-time-group-inner>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</draggable>
|
||||
@ -470,7 +477,7 @@ const expandClick = component => {
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
font-size: 12px;
|
||||
padding: 0 2px 0 20px;
|
||||
padding: 0 2px 0 28px;
|
||||
user-select: none;
|
||||
|
||||
.component-icon {
|
||||
@ -513,7 +520,7 @@ const expandClick = component => {
|
||||
.component-base {
|
||||
opacity: 1;
|
||||
}
|
||||
width: 70px !important;
|
||||
width: 55px !important;
|
||||
}
|
||||
}
|
||||
|
||||
@ -521,7 +528,7 @@ const expandClick = component => {
|
||||
.component-base {
|
||||
opacity: 0;
|
||||
}
|
||||
width: 0px;
|
||||
width: 0;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
@ -575,7 +582,7 @@ const expandClick = component => {
|
||||
}
|
||||
|
||||
.icon-container-show {
|
||||
width: 70px !important;
|
||||
width: 55px !important;
|
||||
}
|
||||
|
||||
.icon-container-lock {
|
||||
|
@ -0,0 +1,598 @@
|
||||
<script lang="ts" setup>
|
||||
import group from '@/assets/svg/group.svg'
|
||||
import bar from '@/assets/svg/bar.svg'
|
||||
import dbMoreWeb from '@/assets/svg/db-more-web.svg'
|
||||
import dvMoreTimeClock from '@/assets/svg/dv-more-time-clock.svg'
|
||||
import dvPictureReal from '@/assets/svg/dv-picture-real.svg'
|
||||
import dvTab from '@/assets/svg/dv-tab.svg'
|
||||
import iconStream from '@/assets/svg/icon-stream.svg'
|
||||
import iconVideo from '@/assets/svg/icon-video.svg'
|
||||
import icon_graphical from '@/assets/svg/icon_graphical.svg'
|
||||
import icon_search from '@/assets/svg/icon_search.svg'
|
||||
import other_material_board from '@/assets/svg/other_material_board.svg'
|
||||
import other_material_icon from '@/assets/svg/other_material_icon.svg'
|
||||
import scrollText from '@/assets/svg/scroll-text.svg'
|
||||
import areaOrigin from '@/assets/svg/area-origin.svg'
|
||||
import areaStackOrigin from '@/assets/svg/area-stack-origin.svg'
|
||||
import barGroupOrigin from '@/assets/svg/bar-group-origin.svg'
|
||||
import barGroupStackOrigin from '@/assets/svg/bar-group-stack-origin.svg'
|
||||
import barHorizontalOrigin from '@/assets/svg/bar-horizontal-origin.svg'
|
||||
import barOrigin from '@/assets/svg/bar-origin.svg'
|
||||
import barRangeOrigin from '@/assets/svg/bar-range-origin.svg'
|
||||
import barStackHorizontalOrigin from '@/assets/svg/bar-stack-horizontal-origin.svg'
|
||||
import barStackOrigin from '@/assets/svg/bar-stack-origin.svg'
|
||||
import bidirectionalBarOrigin from '@/assets/svg/bidirectional-bar-origin.svg'
|
||||
import bubbleMapOrigin from '@/assets/svg/bubble-map-origin.svg'
|
||||
import chartMixGroupOrigin from '@/assets/svg/chart-mix-group-origin.svg'
|
||||
import chartMixOrigin from '@/assets/svg/chart-mix-origin.svg'
|
||||
import chartMixStackOrigin from '@/assets/svg/chart-mix-stack-origin.svg'
|
||||
import chartMixDualLineOrigin from '@/assets/svg/chart-mix-dual-line-origin.svg'
|
||||
import flowMapOrigin from '@/assets/svg/flow-map-origin.svg'
|
||||
import funnelOrigin from '@/assets/svg/funnel-origin.svg'
|
||||
import gaugeOrigin from '@/assets/svg/gauge-origin.svg'
|
||||
import heatMapOrigin from '@/assets/svg/heat-map-origin.svg'
|
||||
import indicatorOrigin from '@/assets/svg/indicator-origin.svg'
|
||||
import lineOrigin from '@/assets/svg/line-origin.svg'
|
||||
import liquidOrigin from '@/assets/svg/liquid-origin.svg'
|
||||
import mapOrigin from '@/assets/svg/map-origin.svg'
|
||||
import percentageBarStackHorizontalOrigin from '@/assets/svg/percentage-bar-stack-horizontal-origin.svg'
|
||||
import percentageBarStackOrigin from '@/assets/svg/percentage-bar-stack-origin.svg'
|
||||
import pieDonutOrigin from '@/assets/svg/pie-donut-origin.svg'
|
||||
import pieDonutRoseOrigin from '@/assets/svg/pie-donut-rose-origin.svg'
|
||||
import pieOrigin from '@/assets/svg/pie-origin.svg'
|
||||
import pieRoseOrigin from '@/assets/svg/pie-rose-origin.svg'
|
||||
import progressBarOrigin from '@/assets/svg/progress-bar-origin.svg'
|
||||
import quadrantOrigin from '@/assets/svg/quadrant-origin.svg'
|
||||
import radarOrigin from '@/assets/svg/radar-origin.svg'
|
||||
import richTextOrigin from '@/assets/svg/rich-text-origin.svg'
|
||||
import sankeyOrigin from '@/assets/svg/sankey-origin.svg'
|
||||
import scatterOrigin from '@/assets/svg/scatter-origin.svg'
|
||||
import stockLineOrigin from '@/assets/svg/stock-line-origin.svg'
|
||||
import symbolicMapOrigin from '@/assets/svg/symbolic-map-origin.svg'
|
||||
import tableInfoOrigin from '@/assets/svg/table-info-origin.svg'
|
||||
import tableNormalOrigin from '@/assets/svg/table-normal-origin.svg'
|
||||
import tablePivotOrigin from '@/assets/svg/table-pivot-origin.svg'
|
||||
import treemapOrigin from '@/assets/svg/treemap-origin.svg'
|
||||
import waterfallOrigin from '@/assets/svg/waterfall-origin.svg'
|
||||
import wordCloudOrigin from '@/assets/svg/word-cloud-origin.svg'
|
||||
import tHeatmapOrigin from '@/assets/svg/t-heatmap-origin.svg'
|
||||
import dvEyeClose from '@/assets/svg/dv-eye-close.svg'
|
||||
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'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { ElIcon, ElRow } from 'element-plus-secondary'
|
||||
import Icon from '../icon-custom/src/Icon.vue'
|
||||
import { nextTick, ref, toRefs } 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 circlePackingOrigin from '@/assets/svg/circle-packing-origin.svg'
|
||||
import RealTimeTab from '@/components/data-visualization/RealTimeTab.vue'
|
||||
const dropdownMore = ref(null)
|
||||
const lockStore = lockStoreWithOut()
|
||||
|
||||
const dvMainStore = dvMainStoreWithOut()
|
||||
const snapshotStore = snapshotStoreWithOut()
|
||||
const layerStore = layerStoreWithOut()
|
||||
const composeStore = composeStoreWithOut()
|
||||
|
||||
const { areaData } = storeToRefs(composeStore)
|
||||
|
||||
const { curComponent, canvasViewInfo } = storeToRefs(dvMainStore)
|
||||
|
||||
const props = defineProps({
|
||||
tabPosition: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: 'main'
|
||||
},
|
||||
componentData: []
|
||||
})
|
||||
|
||||
const { componentData } = toRefs(props)
|
||||
|
||||
const getComponent = index => {
|
||||
return componentData.value[componentData.value.length - 1 - index]
|
||||
}
|
||||
const transformIndex = index => {
|
||||
return componentData.value.length - 1 - index
|
||||
}
|
||||
|
||||
const onClick = index => {
|
||||
setCurComponent(index)
|
||||
//其他情况点击清理选择区域
|
||||
areaData.value.components.splice(0, areaData.value.components.length)
|
||||
}
|
||||
|
||||
const setCurComponent = index => {
|
||||
dvMainStore.setCurComponent({ component: componentData.value[index], index })
|
||||
}
|
||||
|
||||
let nameEdit = ref(false)
|
||||
let editComponentId = ref('')
|
||||
let inputName = ref('')
|
||||
let nameInput = ref(null)
|
||||
let curEditComponent = null
|
||||
const editComponentName = item => {
|
||||
curEditComponent = curComponent.value
|
||||
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() === curEditComponent.name) {
|
||||
return
|
||||
}
|
||||
curEditComponent.name = inputName.value
|
||||
inputName.value = ''
|
||||
curEditComponent = null
|
||||
}
|
||||
|
||||
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('showComponent')
|
||||
})
|
||||
}
|
||||
|
||||
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 iconMap = {
|
||||
bar: bar,
|
||||
'db-more-web': dbMoreWeb,
|
||||
'dv-more-time-clock': dvMoreTimeClock,
|
||||
'dv-picture-real': dvPictureReal,
|
||||
'dv-tab': dvTab,
|
||||
'icon-stream': iconStream,
|
||||
'icon-video': iconVideo,
|
||||
icon_graphical: icon_graphical,
|
||||
icon_search: icon_search,
|
||||
other_material_board: other_material_board,
|
||||
other_material_icon: other_material_icon,
|
||||
'scroll-text': scrollText,
|
||||
'area-origin': areaOrigin,
|
||||
'area-stack-origin': areaStackOrigin,
|
||||
'bar-group-origin': barGroupOrigin,
|
||||
'bar-group-stack-origin': barGroupStackOrigin,
|
||||
'bar-horizontal-origin': barHorizontalOrigin,
|
||||
'bar-origin': barOrigin,
|
||||
'bar-range-origin': barRangeOrigin,
|
||||
'bar-stack-horizontal-origin': barStackHorizontalOrigin,
|
||||
'bar-stack-origin': barStackOrigin,
|
||||
'bidirectional-bar-origin': bidirectionalBarOrigin,
|
||||
'bubble-map-origin': bubbleMapOrigin,
|
||||
'chart-mix-group-origin': chartMixGroupOrigin,
|
||||
'chart-mix-origin': chartMixOrigin,
|
||||
'chart-mix-stack-origin': chartMixStackOrigin,
|
||||
'chart-mix-dual-line': chartMixDualLineOrigin,
|
||||
'flow-map-origin': flowMapOrigin,
|
||||
'funnel-origin': funnelOrigin,
|
||||
'gauge-origin': gaugeOrigin,
|
||||
'heat-map-origin': heatMapOrigin,
|
||||
'indicator-origin': indicatorOrigin,
|
||||
'line-origin': lineOrigin,
|
||||
'liquid-origin': liquidOrigin,
|
||||
'map-origin': mapOrigin,
|
||||
'percentage-bar-stack-horizontal-origin': percentageBarStackHorizontalOrigin,
|
||||
'percentage-bar-stack-origin': percentageBarStackOrigin,
|
||||
'pie-donut-origin': pieDonutOrigin,
|
||||
'pie-donut-rose-origin': pieDonutRoseOrigin,
|
||||
'pie-origin': pieOrigin,
|
||||
'pie-rose-origin': pieRoseOrigin,
|
||||
'progress-bar-origin': progressBarOrigin,
|
||||
'quadrant-origin': quadrantOrigin,
|
||||
'radar-origin': radarOrigin,
|
||||
'rich-text-origin': richTextOrigin,
|
||||
'sankey-origin': sankeyOrigin,
|
||||
'scatter-origin': scatterOrigin,
|
||||
'stock-line-origin': stockLineOrigin,
|
||||
'symbolic-map-origin': symbolicMapOrigin,
|
||||
'table-info-origin': tableInfoOrigin,
|
||||
'table-normal-origin': tableNormalOrigin,
|
||||
'table-pivot-origin': tablePivotOrigin,
|
||||
'treemap-origin': treemapOrigin,
|
||||
'waterfall-origin': waterfallOrigin,
|
||||
'word-cloud-origin': wordCloudOrigin,
|
||||
't-heatmap-origin': tHeatmapOrigin,
|
||||
group: group,
|
||||
'circle-packing-origin': circlePackingOrigin
|
||||
}
|
||||
const getIconName = item => {
|
||||
if (item.component === 'UserView') {
|
||||
const viewInfo = canvasViewInfo.value[item.id]
|
||||
return iconMap[`${viewInfo.type}-origin`]
|
||||
} else {
|
||||
return iconMap[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 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)
|
||||
})
|
||||
}
|
||||
const expandClick = component => {
|
||||
component['expand'] = !component['expand']
|
||||
}
|
||||
</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>
|
||||
<div
|
||||
:title="getComponent(index)?.name"
|
||||
class="component-item"
|
||||
:class="{
|
||||
'container-item-not-show': !getComponent(index)?.isShow,
|
||||
'component-item-group-tab': tabPosition === 'groupTab',
|
||||
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
|
||||
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"><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
|
||||
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>
|
||||
</div>
|
||||
</template>
|
||||
</draggable>
|
||||
</div>
|
||||
</el-row>
|
||||
<Teleport v-if="editComponentId && nameEdit" :to="editComponentId">
|
||||
<input
|
||||
class="custom-teleport"
|
||||
@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 28px;
|
||||
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: 10px;
|
||||
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: 55px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.icon-container {
|
||||
.component-base {
|
||||
opacity: 0;
|
||||
}
|
||||
width: 0;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
flex-grow: 1;
|
||||
cursor: none;
|
||||
i {
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
.activated {
|
||||
background-color: var(--ed-color-primary-1a, rgba(51, 112, 255, 0.1)) !important;
|
||||
:deep(.component-icon) {
|
||||
color: var(--ed-color-primary);
|
||||
}
|
||||
:deep(.component-label) {
|
||||
color: var(--ed-color-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.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: 55px !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;
|
||||
}
|
||||
}
|
||||
.custom-teleport {
|
||||
background: #1a1a1a !important;
|
||||
}
|
||||
.component-item-group-tab {
|
||||
padding-left: 60px !important;
|
||||
}
|
||||
|
||||
.component-expand {
|
||||
cursor: pointer;
|
||||
height: 16px !important;
|
||||
width: 16px !important;
|
||||
border-radius: 2px;
|
||||
padding: 0 2px;
|
||||
|
||||
.expand-icon {
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: rgba(235, 235, 235, 0.1);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background: rgba(235, 235, 235, 0.1);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="less">
|
||||
.compose-dropdown {
|
||||
position: initial !important;
|
||||
}
|
||||
</style>
|
@ -81,6 +81,7 @@ import { contextmenuStoreWithOut } from '@/store/modules/data-visualization/cont
|
||||
import RealTimeTab from '@/components/data-visualization/RealTimeTab.vue'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import circlePackingOrigin from '@/assets/svg/circle-packing-origin.svg'
|
||||
import { checkJoinGroup } from '@/utils/canvasUtils'
|
||||
const dropdownMore = ref(null)
|
||||
const lockStore = lockStoreWithOut()
|
||||
|
||||
@ -136,16 +137,15 @@ const shiftDataPush = curClickIndex => {
|
||||
indexBegin = curClickIndex
|
||||
indexEnd = laterIndexTrans
|
||||
}
|
||||
const shiftAreaComponents = componentData.value
|
||||
.slice(indexBegin, indexEnd + 1)
|
||||
.filter(
|
||||
component =>
|
||||
!areaDataIdArray.includes(component.id) &&
|
||||
!component.isLock &&
|
||||
component.isShow &&
|
||||
component.category !== 'hidden' &&
|
||||
!['GroupArea', 'DeTabs'].includes(component.component)
|
||||
)
|
||||
const shiftAreaComponents = componentData.value.slice(indexBegin, indexEnd + 1).filter(
|
||||
component =>
|
||||
!areaDataIdArray.includes(component.id) &&
|
||||
!component.isLock &&
|
||||
component.isShow &&
|
||||
component.category !== 'hidden' &&
|
||||
!['GroupArea'].includes(component.component) &&
|
||||
checkJoinGroup(component) // 当前如果是Tab 则tab中不能包含Group
|
||||
)
|
||||
areaData.value.components.push(...shiftAreaComponents)
|
||||
dvMainStore.setCurComponent({ component: null, index: null })
|
||||
}
|
||||
@ -509,7 +509,7 @@ const canvasChange = () => {
|
||||
>
|
||||
<div
|
||||
v-show="['Group', 'DeTabs'].includes(getComponent(index)?.component)"
|
||||
style="width: 22px; padding-left: 3px"
|
||||
style="width: 22px"
|
||||
>
|
||||
<el-icon class="component-expand" @click="expandClick(getComponent(index))">
|
||||
<Icon
|
||||
@ -662,7 +662,7 @@ const canvasChange = () => {
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
font-size: 12px;
|
||||
padding: 0 2px 0 0px;
|
||||
padding: 0 2px 0 8px;
|
||||
user-select: none;
|
||||
|
||||
.component-icon {
|
||||
@ -705,7 +705,7 @@ const canvasChange = () => {
|
||||
.component-base {
|
||||
opacity: 1;
|
||||
}
|
||||
width: 66px !important;
|
||||
max-width: 66px !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
88
core/core-frontend/src/utils/ShapeUtils.ts
Normal file
88
core/core-frontend/src/utils/ShapeUtils.ts
Normal file
@ -0,0 +1,88 @@
|
||||
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
|
||||
import { storeToRefs } from 'pinia'
|
||||
|
||||
const dvMainStore = dvMainStoreWithOut()
|
||||
const { componentData } = storeToRefs(dvMainStore)
|
||||
|
||||
// 检查是否可以加入到分组
|
||||
export function checkJoinGroup(item) {
|
||||
if (item.component === 'DeTabs') {
|
||||
let result = true
|
||||
item.propValue.forEach(tabItem => {
|
||||
tabItem.componentData.forEach(tabComponent => {
|
||||
if (tabComponent.component === 'Group') {
|
||||
result = false
|
||||
}
|
||||
})
|
||||
})
|
||||
return result
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
}
|
||||
// 检查是否可以移入tab
|
||||
export function checkJoinTab(item) {
|
||||
if (item.component === 'Group') {
|
||||
let result = true
|
||||
item.propValue.forEach(groupItem => {
|
||||
if (groupItem.component === 'DeTabs') {
|
||||
result = false
|
||||
}
|
||||
})
|
||||
return result
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// 目前仅允许group中还有一层Tab 或者 Tab中含有一层group
|
||||
export function itemCanvasPathCheck(item, 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 === 'groupInTab') {
|
||||
return Boolean(
|
||||
item.component === 'Group' &&
|
||||
pathMap[pathMap[item.id].id] &&
|
||||
pathMap[pathMap[item.id].id].component === 'DeTabs'
|
||||
)
|
||||
}
|
||||
|
||||
// 当前组件是Tab且在Group中
|
||||
if (checkType === 'tabInGroup') {
|
||||
return Boolean(
|
||||
item.component === 'DeTabs' && pathMap[item.id] && pathMap[item.id].component === 'Group'
|
||||
)
|
||||
}
|
||||
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)
|
||||
})
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user