feat(仪表板、数据大屏): Tab支持单tab内隐藏与显示、排序调整等功能 #17984 (#18119)

This commit is contained in:
王嘉豪
2026-03-19 17:23:10 +08:00
committed by GitHub
parent 2fc1d32f72
commit f93a05cee4
3 changed files with 224 additions and 27 deletions

View File

@@ -13,6 +13,7 @@ import CarouselSetting from '@/custom-component/common/CarouselSetting.vue'
import CommonBorderSetting from '@/custom-component/common/CommonBorderSetting.vue'
import CollapseSwitchItem from '../../components/collapse-switch-item/src/CollapseSwitchItem.vue'
import TabBackgroundOverall from '@/custom-component/de-tabs/TabBackgroundOverall.vue'
import CustomTabsSortSide from '@/custom-component/de-tabs/CustomTabsSortSide.vue'
const snapshotStore = snapshotStoreWithOut()
const { t } = useI18n()
@@ -204,6 +205,7 @@ onMounted(() => {
:themes="themes"
:element="element"
></common-style-set>
<CustomTabsSortSide :themes="themes" :config="element"></CustomTabsSortSide>
</collapse-switch-item>
<el-collapse-item
v-if="styleShow"

View File

@@ -27,6 +27,7 @@
:lazy="isEditMode"
:label="tabItem.title"
:name="tabItem.name"
v-if="!tabItem.hidden"
>
<template #label>
<div class="custom-tab-title" @mousedown.stop>
@@ -90,33 +91,35 @@
v-for="(tabItem, index) in element.propValue"
:class="{ 'switch-hidden': element.editableTabsValue !== tabItem.name }"
>
<de-canvas
v-if="isEdit && !mobileInPc"
:ref="'tabCanvas_' + index"
:component-data="tabItem.componentData"
:canvas-style-data="canvasStyleData"
:canvas-view-info="canvasViewInfo"
:canvas-id="element.id + '--' + tabItem.name"
:class="moveActive ? 'canvas-move-in' : ''"
:canvas-position="'tab'"
:canvas-active="element.editableTabsValue === tabItem.name"
:font-family="fontFamily"
></de-canvas>
<de-preview
v-else
:ref="'dashboardPreview'"
:dv-info="dvInfo"
:cur-gap="curPreviewGap"
:component-data="tabItem.componentData"
:canvas-style-data="{}"
:canvas-view-info="canvasViewInfo"
:canvas-id="element.id + '--' + tabItem.name"
:preview-active="element.editableTabsValue === tabItem.name"
:show-position="showPosition"
:outer-scale="scale"
:font-family="fontFamily"
:outer-search-count="searchCount"
></de-preview>
<template v-if="!tabItem.hidden">
<de-canvas
v-if="isEdit && !mobileInPc"
:ref="'tabCanvas_' + index"
:component-data="tabItem.componentData"
:canvas-style-data="canvasStyleData"
:canvas-view-info="canvasViewInfo"
:canvas-id="element.id + '--' + tabItem.name"
:class="moveActive ? 'canvas-move-in' : ''"
:canvas-position="'tab'"
:canvas-active="element.editableTabsValue === tabItem.name"
:font-family="fontFamily"
></de-canvas>
<de-preview
v-else
:ref="'dashboardPreview'"
:dv-info="dvInfo"
:cur-gap="curPreviewGap"
:component-data="tabItem.componentData"
:canvas-style-data="{}"
:canvas-view-info="canvasViewInfo"
:canvas-id="element.id + '--' + tabItem.name"
:preview-active="element.editableTabsValue === tabItem.name"
:show-position="showPosition"
:outer-scale="scale"
:font-family="fontFamily"
:outer-search-count="searchCount"
></de-preview>
</template>
</div>
</de-custom-tab>
<el-dialog
@@ -359,6 +362,7 @@ function addTab() {
const newTab = {
name: newName,
title: t('visualization.new_tab'),
hidden: false,
componentData: [],
closable: true
}
@@ -723,6 +727,8 @@ onMounted(() => {
eventBus.on('onTabMoveIn-' + element.value.id, componentMoveIn)
eventBus.on('onTabMoveOut-' + element.value.id, componentMoveOut)
eventBus.on('onTabSortChange-' + element.value.id, reShow)
eventBus.on('onTabDelete-' + element.value.id, deleteCur)
eventBus.on('onTabCopy-' + element.value.id, copyCur)
}
currentInstance = getCurrentInstance()
initCarousel()
@@ -749,6 +755,8 @@ onBeforeUnmount(() => {
eventBus.off('onTabMoveIn-' + element.value.id, componentMoveIn)
eventBus.off('onTabMoveOut-' + element.value.id, componentMoveOut)
eventBus.off('onTabSortChange-' + element.value.id, reShow)
eventBus.off('onTabDelete-' + element.value.id, deleteCur)
eventBus.off('onTabCopy-' + element.value.id, copyCur)
}
})
onBeforeMount(() => {

View File

@@ -0,0 +1,187 @@
<template>
<div style="display: flex; width: 100%">
<div style="flex: 1; min-width: 0">
<draggable :list="config.propValue" animation="300" class="drag-list" @end="onSortChange">
<template #item="{ element }">
<span
:key="element.name"
class="item-dimension"
:class="{ 'item-dimension-dark': themes === 'dark' }"
:title="element.title"
>
<el-icon size="20px">
<Icon name="drag"><drag class="svg-icon" /></Icon>
</el-icon>
<span class="item-span">
{{ element.title }}
</span>
</span>
</template>
</draggable>
</div>
<div style="width: 80px">
<div v-for="item in config.propValue" :key="item" class="item-icon">
<el-icon class="component-base" @click="onDelete(item)">
<Icon name="dv-show"><Delete class="svg-icon opt-icon" /></Icon>
</el-icon>
<el-icon
v-show="item.hidden"
class="component-base component-icon-display"
@click="() => (item['hidden'] = false)"
>
<Icon name="dv-eye-close"><dvEyeClose class="svg-icon opt-icon" /></Icon>
</el-icon>
<el-icon
v-show="!item.hidden"
class="component-base"
@click="() => (item['hidden'] = true)"
>
<Icon name="dv-show"><dvShow class="svg-icon opt-icon" /></Icon>
</el-icon>
<el-icon v-show="!item.hidden" class="component-base" @click="onCopy(item)">
<Icon name="dv-show"><CopyDocument class="svg-icon opt-icon" /></Icon>
</el-icon>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import drag from '@/assets/svg/drag.svg'
import draggable from 'vuedraggable'
import { toRefs } from 'vue'
import { snapshotStoreWithOut } from '@/store/modules/data-visualization/snapshot'
import eventBus from '@/utils/eventBus'
import dvEyeClose from '@/assets/svg/dv-eye-close.svg'
import dvShow from '@/assets/svg/dv-show.svg'
const snapshotStore = snapshotStoreWithOut()
const props = withDefaults(
defineProps<{
themes?: EditorTheme
config: any
}>(),
{
themes: 'dark',
config: {
propValue: []
}
}
)
const { config, themes } = toRefs(props)
const onSortChange = () => {
snapshotStore.recordSnapshotCache('tab-sort-save')
eventBus.emit('onTabSortChange-' + config.value.id)
}
const onDelete = item => {
snapshotStore.recordSnapshotCache('tab')
eventBus.emit('onTabDelete-' + config.value.id, deepCopy(item))
}
const onCopy = item => {
snapshotStore.recordSnapshotCache('tab')
eventBus.emit('onTabCopy-' + config.value.id, deepCopy(item))
}
import { ElIcon } from 'element-plus-secondary'
import Icon from '../../components/icon-custom/src/Icon.vue'
import { deepCopy } from '@/utils/utils'
</script>
<style scoped lang="less">
.drag-list {
overflow: auto;
max-height: 400px;
}
.item-icon {
height: 30px;
padding: 2px;
margin: 2px !important;
text-align: left;
color: #606266;
display: flex;
align-items: center;
}
.item-dimension {
padding: 2px;
margin: 2px;
border: solid 1px #eee;
text-align: left;
color: #606266;
/*background-color: rgba(35,46,64,.05);*/
background-color: white;
display: flex;
align-items: center;
}
.item-icon {
cursor: move;
margin: 0 2px;
}
.item-span {
display: inline-block;
width: 100%;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.blackTheme .item-dimension {
border: solid 1px;
border-color: var(--ed-border-color);
color: var(--TextPrimary);
background-color: var(--MainBG);
}
.item-dimension-dark {
border: solid 1px;
border-color: var(--TableBorderColor);
color: var(--TextPrimary);
background-color: var(--MainBG);
}
.item-dimension + .item-dimension {
margin-top: 6px;
}
.item-dimension:hover {
color: #1890ff;
background: #e8f4ff;
border-color: #a3d3ff;
cursor: pointer;
}
.blackTheme .item-dimension:hover {
color: var(--Main);
background: var(--ContentBG);
cursor: pointer;
}
.component-base {
cursor: pointer;
height: 22px !important;
width: 22px !important;
border-radius: 4px;
padding: 0 4px;
color: #a6a6a6;
.opt-icon {
font-size: 16px;
}
&:hover {
background: rgba(235, 235, 235, 0.1);
}
&:active {
background: rgba(235, 235, 235, 0.1);
}
}
</style>