Merge pull request #10924 from dataease/pr@v2.8@feat_hidden-component

Pr@v2.8@feat hidden component
This commit is contained in:
王嘉豪 2024-07-12 13:05:15 +08:00 committed by GitHub
commit 4d27edfe46
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
24 changed files with 772 additions and 43 deletions

View File

@ -3,9 +3,9 @@ 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 { ElIcon, ElRow, ElSwitch } from 'element-plus-secondary'
import Icon from '../icon-custom/src/Icon.vue'
import { nextTick, ref } from 'vue'
import { computed, nextTick, ref } from 'vue'
import draggable from 'vuedraggable'
import { lockStoreWithOut } from '@/store/modules/data-visualization/lock'
import ContextMenuAsideDetails from '@/components/data-visualization/canvas/ContextMenuAsideDetails.vue'
@ -22,7 +22,8 @@ const composeStore = composeStoreWithOut()
const { areaData, isCtrlOrCmdDown, isShiftDown, laterIndex } = storeToRefs(composeStore)
const { componentData, curComponent, canvasViewInfo } = storeToRefs(dvMainStore)
const { componentData, canvasStyleData, curComponent, canvasViewInfo, canvasState } =
storeToRefs(dvMainStore)
const getComponent = index => {
return componentData.value[componentData.value.length - 1 - index]
}
@ -34,6 +35,13 @@ const areaDataPush = component => {
areaData.value.components.push(component)
}
}
const hiddenAreaActive = computed(
() => canvasState.value.curPointArea === 'hidden' && !curComponent.value
)
const baseAreaActive = computed(
() => canvasState.value.curPointArea === 'base' && !curComponent.value
)
// shift
// 1.laterIndexlaterIndex=0;
// 2.index curClickIndex;
@ -59,6 +67,16 @@ const shiftDataPush = curClickIndex => {
dvMainStore.setCurComponent({ component: null, index: null })
}
const hiddenAreaOnClick = (e, element) => {
let indexResult
componentData.value.forEach((component, index) => {
if (element.id === component.id) {
indexResult = index
}
})
dvMainStore.setCurComponent({ component: element, index: indexResult })
}
const onClick = (e, index) => {
// laterIndex=0
if (!curComponent.value) {
@ -149,6 +167,14 @@ const showComponent = () => {
})
}
const popComponentData = computed(() =>
componentData.value.filter(ele => ele.category && ele.category === 'hidden')
)
const baseComponentData = computed(() =>
componentData.value.filter(ele => ele.category !== 'hidden' && ele.component !== 'GroupArea')
)
const dragOnEnd = ({ oldIndex, newIndex }) => {
const source = componentData.value[newIndex]
const comLength = componentData.value.length
@ -204,12 +230,94 @@ const handleContextMenu = e => {
document.body.removeChild(customContextMenu)
})
}
const areaClick = area => {
dvMainStore.setCurComponent({ component: null, index: null })
dvMainStore.canvasStateChange({ key: 'curPointArea', value: area })
}
</script>
<template>
<!--为了保持图层视觉上的一致性 这里进行数组的倒序排列 相应的展示和移动按照倒序处理-->
<div class="real-time-component-list">
<button hidden="true" id="close-button"></button>
<div class="layer-area" @click="areaClick('hidden')" :class="{ activated: hiddenAreaActive }">
<span>弹窗区域({{ popComponentData.length }})</span>
<el-switch v-model="canvasStyleData.popupAvailable" size="small" />
</div>
<el-row class="list-wrap">
<div class="list-container" @contextmenu="handleContextMenu">
<draggable
@end="dragOnEnd"
:list="popComponentData"
animation="100"
class="drag-list"
item-key="id"
>
<template #item="{ element, index }">
<div>
<div
:title="element.name"
class="component-item"
:class="{
'container-item-not-show': !element.isShow,
activated:
(curComponent && curComponent?.id === element?.id) ||
areaData.components.includes(element)
}"
@click="hiddenAreaOnClick($event, element)"
>
<div style="width: 22px; padding-left: 3px"></div>
<el-icon class="component-icon">
<Icon :name="getIconName(element)"></Icon>
</el-icon>
<span
:id="`component-label-${element?.id}`"
class="component-label"
@dblclick="editComponentName(element)"
>
{{ element?.name }}
</span>
<div
v-show="!nameEdit || (nameEdit && curComponent?.id !== element?.id)"
class="icon-container"
:class="{
'icon-container-show': !element?.isShow
}"
>
<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" class="opt-icon"></Icon>
</el-icon>
</span>
<template #dropdown>
<context-menu-aside-details
:element="element"
@close="menuAsideClose($event, index)"
></context-menu-aside-details>
</template>
</el-dropdown>
</div>
</div>
</div>
</template>
</draggable>
</div>
</el-row>
<div
class="layer-area layer-screen"
@click="areaClick('base')"
:class="{ activated: baseAreaActive }"
>
<span>大屏区域({{ baseComponentData.length }})</span>
</div>
<el-row class="list-wrap">
<div class="list-container" @contextmenu="handleContextMenu">
<draggable
@ -222,7 +330,10 @@ const handleContextMenu = e => {
<template #item="{ index }">
<div>
<div
v-show="getComponent(index)?.component !== 'GroupArea'"
v-show="
getComponent(index)?.component !== 'GroupArea' &&
getComponent(index)?.category !== 'hidden'
"
:title="getComponent(index)?.name"
class="component-item"
:class="{
@ -519,6 +630,43 @@ const handleContextMenu = e => {
color: #5f5f5f !important;
}
}
.layer-area {
font-size: 12px;
font-weight: bold;
height: 36px;
line-height: 36px;
padding: 0 8px;
display: flex;
cursor: pointer;
align-items: center;
justify-content: space-between;
&:hover {
background-color: rgba(235, 235, 235, 0.1);
}
:deep(.ed-switch.is-checked .ed-switch__core > .ed-switch__action) {
left: calc(100% - 12px);
}
:deep(span.ed-switch__core) {
min-width: 24px;
border: none;
height: 6px;
border-radius: 3px;
.ed-switch__action {
left: 0;
box-shadow: 0 2px 4px rgba(31, 35, 41, 0.12);
}
}
}
.activated {
background-color: var(--ed-color-primary-1a, rgba(51, 112, 255, 0.1)) !important;
color: var(--ed-color-primary);
}
.layer-screen {
border-top: rgba(255, 255, 255, 0.15) 1px solid;
}
</style>
<style lang="less">

View File

@ -0,0 +1,11 @@
<script setup lang="ts">
</script>
<template>
</template>
<style scoped lang="less">
</style>

View File

@ -44,14 +44,15 @@ import PointShadow from '@/components/data-visualization/canvas/PointShadow.vue'
import DragInfo from '@/components/visualization/common/DragInfo.vue'
import { activeWatermark } from '@/components/watermark/watermark'
import { personInfoApi } from '@/api/user'
import ComponentHangPopver from '@/custom-component/independent-hang/ComponentHangPopver.vue'
import PopArea from '@/custom-component/pop-area/Component.vue'
const snapshotStore = snapshotStoreWithOut()
const dvMainStore = dvMainStoreWithOut()
const composeStore = composeStoreWithOut()
const contextmenuStore = contextmenuStoreWithOut()
const { curComponent, dvInfo, editMode, tabMoveOutComponentId } = storeToRefs(dvMainStore)
const { curComponent, dvInfo, editMode, tabMoveOutComponentId, canvasState } =
storeToRefs(dvMainStore)
const { editorMap, areaData } = storeToRefs(composeStore)
const emits = defineEmits(['scrollCanvasToTop'])
const props = defineProps({
@ -67,6 +68,11 @@ const props = defineProps({
type: Array,
required: true
},
popComponentData: {
type: Array,
required: false,
default: () => []
},
canvasViewInfo: {
type: Object,
required: true
@ -1398,6 +1404,11 @@ const groupAreaClickChange = async () => {
}
}
// v-if 使
const popAreaAvailable = computed(
() => canvasStyleData.value?.popupAvailable && isMainCanvas(canvasId.value)
)
onMounted(() => {
if (isMainCanvas(canvasId.value)) {
initSnapshotTimer()
@ -1460,6 +1471,18 @@ defineExpose({
:component-data="componentData"
:canvas-id="canvasId"
></canvas-opt-bar>
<!-- 弹框区域 -->
<PopArea
v-if="popAreaAvailable"
:dv-info="dvInfo"
:canvas-id="canvasId"
:canvas-style-data="canvasStyleData"
:canvasViewInfo="canvasViewInfo"
:pop-component-data="popComponentData"
:scale="curBaseScale"
:canvas-state="canvasState"
:show-position="'popEdit'"
></PopArea>
<!-- 网格线 -->
<drag-shadow
v-if="infoBox && infoBox.moveItem && editMode !== 'preview'"

View File

@ -1,16 +1,18 @@
<script setup lang="ts">
import { getStyle } from '@/utils/style'
import eventBus from '@/utils/eventBus'
import { ref, onMounted, toRefs, getCurrentInstance, computed } from 'vue'
import { ref, onMounted, toRefs, getCurrentInstance, computed, nextTick } from 'vue'
import findComponent from '@/utils/components'
import { downloadCanvas, imgUrlTrans } from '@/utils/imgUtils'
import ComponentEditBar from '@/components/visualization/ComponentEditBar.vue'
import ComponentSelector from '@/components/visualization/ComponentSelector.vue'
import { useEmitt } from '@/hooks/web/useEmitt'
import Board from '@/components/de-board/Board.vue'
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
const componentWrapperInnerRef = ref(null)
const componentEditBarRef = ref(null)
const dvMainStore = dvMainStoreWithOut()
const props = defineProps({
active: {
@ -100,6 +102,9 @@ const handleInnerMouseDown = e => {
e.stopPropagation()
e.preventDefault()
}
if (showPosition.value.includes('popEdit')) {
onClick(e)
}
}
onMounted(() => {
@ -112,12 +117,14 @@ onMounted(() => {
})
})
const onClick = () => {
const events = config.value.events
Object.keys(events).forEach(event => {
currentInstance.ctx[event](events[event])
})
eventBus.emit('v-click', config.value.id)
const onClick = e => {
e.preventDefault()
e.stopPropagation()
//
eventBus.emit('componentClick')
dvMainStore.setInEditorStatus(true)
dvMainStore.setClickComponentStatus(true)
dvMainStore.setCurComponent({ component: config.value, index: index.value })
}
const getComponentStyleDefault = style => {
@ -192,7 +199,6 @@ const deepScale = computed(() => scale.value / 100)
<div
class="wrapper-outer"
:class="showPosition + '-' + config.component"
@click="onClick"
@mousedown="handleInnerMouseDown"
@mouseenter="onMouseEnter"
>

View File

@ -19,7 +19,7 @@ const layerStore = layerStoreWithOut()
const composeStore = composeStoreWithOut()
const { areaData } = storeToRefs(composeStore)
const { curComponent } = storeToRefs(dvMainStore)
const { curComponent, componentData } = storeToRefs(dvMainStore)
const emit = defineEmits(['close', 'rename'])
const { emitter } = useEmitt()
const props = defineProps({
@ -31,6 +31,10 @@ const props = defineProps({
const { activePosition } = toRefs(props)
const popComponentDataLength = computed(
() => componentData.value.filter(ele => ele.category === 'hidden').length
)
const lock = () => {
snapshotStore.recordSnapshotCache()
lockStore.lock()
@ -80,7 +84,15 @@ const show = () => {
layerStore.showComponent()
menuOpt('show')
}
const categoryChange = type => {
if (curComponent.value) {
snapshotStore.recordSnapshotCache()
curComponent.value['category'] = type
if (type === 'hidden') {
dvMainStore.canvasStateChange({ key: 'curPointArea', value: 'hidden' })
}
}
}
const rename = () => {
emit('rename')
menuOpt('rename')
@ -153,7 +165,12 @@ const handleComposeMouseDown = e => {
}
const composeDivider = computed(() => {
return !(!curComponent || curComponent['isLock'] || curComponent['component'] != 'Group')
return !(
!curComponent ||
curComponent['isLock'] ||
curComponent['component'] != 'Group' ||
curComponent.category === 'hidden'
)
})
const isGroupArea = computed(() => {
@ -211,14 +228,33 @@ const editQueryCriteria = () => {
取消组合
</li>
<el-divider class="custom-divider" v-show="composeDivider" />
<template v-if="curComponent && !isGroupArea">
<template v-if="!curComponent['isLock']">
<template v-if="curComponent">
<template v-if="!curComponent['isLock'] && curComponent.category === 'hidden'">
<li @click="categoryChange('base')">移动到大屏显示区</li>
<li @click="editQueryCriteria">编辑</li>
<li v-if="activePosition === 'aside'" @click="rename">重命名</li>
<li @click="copy">复制</li>
<li @click="paste">粘贴</li>
<el-divider class="custom-divider" />
<li @click="deleteComponent">删除</li>
</template>
<template v-if="!curComponent['isLock'] && curComponent.category !== 'hidden'">
<li v-if="curComponent.component === 'VQuery'" @click="editQueryCriteria">编辑</li>
<li @click="upComponent">上移一层</li>
<li @click="upComponent">上移一层</li>
<li @click="downComponent">下移一层</li>
<li @click="topComponent">置于顶层</li>
<li @click="bottomComponent">置于底层</li>
<li
@click="categoryChange('hidden')"
v-show="
curComponent['category'] === 'base' &&
curComponent.component === 'VQuery' &&
popComponentDataLength === 0
"
>
移动到大屏弹框区
</li>
<el-divider class="custom-divider" />
<li @click="hide" v-show="curComponent['isShow']">隐藏</li>
<li @click="show" v-show="!curComponent['isShow']">取消隐藏</li>
@ -231,7 +267,7 @@ const editQueryCriteria = () => {
<el-divider class="custom-divider" />
<li @click="deleteComponent">删除</li>
</template>
<li v-else @click="unlock">解锁</li>
<li v-if="curComponent['isLock']" @click="unlock">解锁</li>
</template>
<li v-else-if="!curComponent && !areaData.components.length" @click="paste">粘贴</li>
</ul>

View File

@ -14,9 +14,12 @@ import { activeWatermark } from '@/components/watermark/watermark'
import { personInfoApi } from '@/api/user'
import router from '@/router'
import { XpackComponent } from '@/components/plugin'
import PopArea from '@/custom-component/pop-area/Component.vue'
import CanvasFilterBtn from '@/custom-component/canvas-filter-btn/Component.vue'
const dvMainStore = dvMainStoreWithOut()
const { pcMatrixCount, curComponent, mobileInPc } = storeToRefs(dvMainStore)
const { pcMatrixCount, curComponent, mobileInPc, canvasState } = storeToRefs(dvMainStore)
const openHandler = ref(null)
const props = defineProps({
canvasStyleData: {
type: Object,
@ -96,6 +99,14 @@ const dashboardActive = computed(() => {
const isReport = computed(() => {
return !!router.currentRoute.value.query?.report
})
const popComponentData = computed(() =>
componentData.value.filter(ele => ele.category && ele.category === 'hidden')
)
const baseComponentData = computed(() =>
componentData.value.filter(ele => ele.category !== 'hidden' && ele.component !== 'GroupArea')
)
const canvasStyle = computed(() => {
let style = {}
if (canvasStyleData.value && canvasStyleData.value.width && isMainCanvas(canvasId.value)) {
@ -163,7 +174,11 @@ const resetLayout = () => {
? scaleMin.value * 1.2
: outerScale.value * 100
} else {
changeRefComponentsSizeWithScale(componentData.value, canvasStyleData.value, scaleMin.value)
changeRefComponentsSizeWithScale(
baseComponentData.value,
canvasStyleData.value,
scaleMin.value
)
}
}
})
@ -250,7 +265,7 @@ const winMsgHandle = event => {
) {
const attachParams = msgInfo.params
if (attachParams) {
dvMainStore.addOuterParamsFilter(attachParams, componentData.value, 'outer')
dvMainStore.addOuterParamsFilter(attachParams, baseComponentData.value, 'outer')
}
}
}
@ -282,6 +297,9 @@ const userViewEnlargeOpen = (opt, item) => {
}
const handleMouseDown = () => {
dvMainStore.setCurComponent({ component: null, index: null })
if (!curComponent.value || (curComponent.value && curComponent.value.category !== 'hidden')) {
dvMainStore.canvasStateChange({ key: 'curPointArea', value: 'base' })
}
}
const onPointClick = param => {
@ -309,6 +327,16 @@ const onPointClick = param => {
console.warn('de_inner_params send error')
}
}
// v-if 使
const popAreaAvailable = computed(
() => canvasStyleData.value?.popupAvailable && isMainCanvas(canvasId.value)
)
const filterBtnShow = computed(
() => popAreaAvailable.value && popComponentData.value && popComponentData.value.length > 0
)
defineExpose({
restore
})
@ -322,13 +350,27 @@ defineExpose({
ref="previewCanvas"
@mousedown="handleMouseDown"
>
<!--弹框触发区域-->
<canvas-filter-btn v-if="filterBtnShow"></canvas-filter-btn>
<!-- 弹框区域 -->
<PopArea
v-if="popAreaAvailable"
:dv-info="dvInfo"
:canvas-id="canvasId"
:canvas-style-data="canvasStyleData"
:canvasViewInfo="canvasViewInfo"
:pop-component-data="popComponentData"
:scale="scaleMin"
:canvas-state="canvasState"
:show-position="'preview'"
></PopArea>
<canvas-opt-bar
:canvas-id="canvasId"
:canvas-style-data="canvasStyleData"
:component-data="componentData"
:component-data="baseComponentData"
></canvas-opt-bar>
<ComponentWrapper
v-for="(item, index) in componentData"
v-for="(item, index) in baseComponentData"
v-show="item.isShow"
:active="item.id === (curComponent || {})['id']"
:canvas-id="canvasId"

View File

@ -0,0 +1,81 @@
<!-- IconSlider.vue -->
<template>
<el-tooltip offset="18" effect="dark" placement="left" content="查询">
<div class="canvas-filter">
<div class="icon-slider" @mouseenter="slideOut" @mouseleave="slideBack">
<div
class="icon-container"
:class="{ 'icon-container-active': filterActive }"
:style="{ transform: `translateX(${offset}px)` }"
@click="popAreaActiveChange"
>
<el-icon><Filter /></el-icon>
</div>
</div>
</div>
</el-tooltip>
</template>
<script lang="ts" setup>
import { computed, ref } from 'vue'
import { ElTooltip } from 'element-plus-secondary'
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
import { storeToRefs } from 'pinia'
const dvMainStore = dvMainStoreWithOut()
const offset = ref(0)
const slideDistance = ref(14) //
const { canvasState } = storeToRefs(dvMainStore)
const filterActive = computed(() => canvasState.value.curPointArea === 'hidden')
const slideOut = () => {
offset.value = -slideDistance.value
}
const popAreaActiveChange = () => {
dvMainStore.popAreaActiveSwitch()
}
const slideBack = () => {
offset.value = 0
}
</script>
<style lang="less" scoped>
.canvas-filter {
position: absolute;
right: -14px;
bottom: 50px;
width: 28px;
height: 32px;
}
.icon-slider {
position: relative;
z-index: 100;
width: 28px;
height: 32px;
}
.icon-container {
transition: transform 0.3s ease; /* 过渡动画 */
background: rgba(26, 26, 26, 1);
font-size: 14px;
border: 1px solid rgba(67, 67, 67, 1);
border-radius: 16px 0 0 16px;
padding: 6px 0 0 6px;
cursor: pointer;
&:hover {
background: rgba(235, 235, 235, 0.1);
}
&:active {
background: rgba(235, 235, 235, 0.2);
}
}
.icon-container-active {
transform: translateX(-14px) !important;
}
img {
max-width: 100%;
max-height: 100%;
}
</style>

View File

@ -9,6 +9,7 @@ import { useI18n } from '@/hooks/web/useI18n'
import elementResizeDetectorMaker from 'element-resize-detector'
import { snapshotStoreWithOut } from '@/store/modules/data-visualization/snapshot'
import CommonStyleSet from '@/custom-component/common/CommonStyleSet.vue'
import CommonEvent from '@/custom-component/common/CommonEvent.vue'
const snapshotStore = snapshotStoreWithOut()
const { t } = useI18n()
@ -87,6 +88,12 @@ const colorPickerWidth = computed(() => {
}
})
//
const eventsShow = computed(() => {
return false
// return !dashboardActive.value && ['Picture'].includes(element.value.component)
})
const backgroundCustomShow = computed(() => {
return (
dashboardActive.value ||
@ -149,6 +156,15 @@ const stopEvent = e => {
:element="element"
></common-style-set>
</el-collapse-item>
<el-collapse-item
v-if="element && element.events && eventsShow"
:effect="themes"
title="事件"
name="style"
class="common-style-area"
>
<common-event :themes="themes" :element="element"></common-event>
</el-collapse-item>
</el-collapse>
</div>
</template>

View File

@ -0,0 +1,55 @@
<script setup lang="ts">
import { computed, toRefs } from 'vue'
import { ElFormItem } from 'element-plus-secondary'
import { snapshotStoreWithOut } from '@/store/modules/data-visualization/snapshot'
const snapshotStore = snapshotStoreWithOut()
const props = withDefaults(
defineProps<{
themes?: EditorTheme
element: any
}>(),
{
themes: 'dark'
}
)
const { themes, element } = toRefs(props)
const eventsInfo = computed(() => {
return element.value.events
})
const onEventChange = () => {
snapshotStore.recordSnapshotCache('renderChart')
}
</script>
<template>
<el-row class="custom-row">
<el-form label-position="top">
<el-form-item class="form-item" :class="'form-item-' + themes">
<el-checkbox
:effect="themes"
size="small"
v-model="eventsInfo.checked"
@change="onEventChange"
>开启事件绑定</el-checkbox
>
</el-form-item>
<el-form-item class="form-item" :class="'form-item-' + themes" style="margin-bottom: 8px">
<el-radio-group
:effect="themes"
v-model="eventsInfo.type"
class="radio-span"
@change="onEventChange"
>
<el-radio label="displayChange" :effect="themes"> 开启弹框区 </el-radio>
</el-radio-group>
</el-form-item>
</el-form>
</el-row>
</template>
<style scoped lang="less"></style>

View File

@ -99,6 +99,8 @@ const outerStyle = computed(() => {
}
})
const curShadowShow = computed(() => curComponent.value && curComponent.value.category !== 'hidden')
defineExpose({
rulerScroll
})
@ -115,7 +117,7 @@ defineExpose({
<div class="ruler-shadow" :style="outerStyle"></div>
<div :style="wStyle" class="ruler-outer-scroll">
<div class="ruler" :style="{ width: `${scaleWidth}px` }">
<div v-if="curComponent" :style="curComponentShadow" class="cur-shadow"></div>
<div v-if="curShadowShow" :style="curComponentShadow" class="cur-shadow"></div>
<div class="ruler-line" :style="{ width: `${scaleWidth}px` }"></div>
<div
v-for="(tick, index) in ticks"
@ -144,7 +146,7 @@ defineExpose({
transform: rotate(90deg);
overflow-y: auto;
overflow-x: hidden;
z-index: 1;
z-index: 2;
.ruler {
.ruler-line {
top: 0;

View File

@ -8,6 +8,18 @@ export const commonStyle = {
opacity: 1
}
export const BASE_EVENTS = {
checked: false,
type: 'displayChange', // openHidden jump
jump: {
value: null
},
displayChange: {
value: true, // 事件当前值 false
target: 'all'
}
}
// 流媒体视频信息配置
export const STREAMMEDIALINKS = {
videoType: 'flv',
@ -159,12 +171,13 @@ export const COMMON_COMPONENT_BACKGROUND_MAP = {
export const commonAttr = {
animations: [],
canvasId: 'canvas-main',
events: {},
events: BASE_EVENTS,
groupStyle: {}, // 当一个组件成为 Group 的子组件时使用
isLock: false, // 是否锁定组件
maintainRadio: false, // 布局时保持宽高比例
aspectRatio: 1, // 锁定时的宽高比例
isShow: true, // 是否显示组件
category: 'base', //组件类型 base 基础组件 hidden隐藏组件
// 当前组件动作
dragging: false,
resizing: false,

View File

@ -4,7 +4,7 @@ import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
import { storeToRefs } from 'pinia'
import CanvasGroup from '@/custom-component/common/CanvasGroup.vue'
import { deepCopy } from '@/utils/utils'
import { DEFAULT_CANVAS_STYLE_DATA_DARK } from '@/views/chart/components/editor/util/dataVisualiztion'
import { DEFAULT_CANVAS_STYLE_DATA_DARK } from '@/views/chart/components/editor/util/dataVisualization'
import { groupSizeStyleAdaptor } from '@/utils/style'
const dvMainStore = dvMainStoreWithOut()
const { canvasStyleData, curComponent } = storeToRefs(dvMainStore)

View File

@ -1,5 +1,5 @@
<template>
<div class="pic-main">
<div class="pic-main" @click="onPictureClick">
<img
draggable="false"
v-if="propValue['url']"
@ -20,6 +20,9 @@
import { CSSProperties, computed, nextTick, toRefs } from 'vue'
import { imgUrlTrans } from '@/utils/imgUtils'
import eventBus from '@/utils/eventBus'
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
const dvMainStore = dvMainStoreWithOut()
const props = defineProps({
propValue: {
type: String,
@ -46,7 +49,16 @@ const imageAdapter = computed(() => {
}
return style as CSSProperties
})
const onPictureClick = e => {
if (element.value.events && element.value.events.checked) {
if (element.value.events.type === 'displayChange') {
//
nextTick(() => {
dvMainStore.popAreaActiveSwitch()
})
}
}
}
const uploadImg = () => {
nextTick(() => {
eventBus.emit('uploadImg')
@ -59,6 +71,7 @@ const uploadImg = () => {
overflow: hidden;
width: 100%;
height: 100%;
cursor: pointer;
}
.pic-upload {
display: flex;

View 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>

View File

@ -0,0 +1,205 @@
<template>
<!--此区域暂时放到类似视图和分组平行的组件作为后续扩展使用但当前版本只作为类似MarkLine 和canvasCore平行组件 仅做区域显示使用-->
<div class="pop-area" :style="popCanvasStyle" @mousedown.stop @mousedup.stop>
<div style="width: 100%; height: 100%">
<div v-if="popComponentData && popComponentData.length > 0" class="pop-content">
<!--使用ComponentWrapper 保留扩展能力-->
<ComponentWrapper
v-for="(item, index) in popComponentData"
:id="'component-pop-' + item.id"
:view-info="canvasViewInfo[item.id]"
:key="index"
:config="item"
:index="index"
:dv-info="dvInfo"
:show-position="showPosition"
:style="customPopStyle"
:scale="innerScale"
/>
</div>
<div
v-else
class="pop-area-main"
:class="{ 'pop-area-active': areaActive }"
:style="baseStyle"
@drop="handleDrop"
@dragover="handleDragOver"
@dragleave="handleDragLeave"
>
<span>可点击或拖拽查询组件到此位置点击预览可查看弹窗区</span>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { computed, onBeforeUnmount, onMounted, ref, toRefs } from 'vue'
import { findDragComponent } from '@/utils/canvasUtils'
import { guid } from '@/views/visualized/data/dataset/form/util'
import { changeComponentSizeWithScale } from '@/utils/changeComponentsSizeWithScale'
import { adaptCurThemeCommonStyle } from '@/utils/canvasStyle'
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
import { snapshotStoreWithOut } from '@/store/modules/data-visualization/snapshot'
import eventBus from '@/utils/eventBus'
import ComponentWrapper from '@/components/data-visualization/canvas/ComponentWrapper.vue'
import { ElMessage } from 'element-plus-secondary'
const dvMainStore = dvMainStoreWithOut()
const snapshotStore = snapshotStoreWithOut()
const areaActive = ref(false)
const props = defineProps({
dvInfo: {
type: Object,
required: true
},
canvasStyleData: {
type: Object,
required: true
},
popComponentData: {
type: Array,
required: true
},
canvasViewInfo: {
type: Object,
required: true
},
canvasId: {
type: String,
required: false,
default: 'canvas-main'
},
scale: {
type: Number,
required: false,
default: 1
},
showPosition: {
type: String,
required: false,
default: 'preview'
},
canvasState: {
type: Object,
required: true
}
})
const { canvasStyleData, popComponentData, canvasViewInfo, scale, canvasState } = toRefs(props)
const baseStyle = computed(() => {
return {
fontSize: 30 * props.scale + 'px',
height: canvasStyleData.value.height * props.scale * 0.15 + 'px'
}
})
const innerScale = computed(() =>
props.showPosition === 'preview' ? props.scale : props.scale * 100
)
const handleDragOver = e => {
areaActive.value = true
e.preventDefault()
e.dataTransfer.dropEffect = 'copy'
}
const handleDragLeave = e => {
areaActive.value = false
}
const handleDrop = e => {
areaActive.value = false
//
if (!popComponentData.value || popComponentData.value.length === 0) {
e.preventDefault()
e.stopPropagation()
const componentInfo = e.dataTransfer.getData('id')
if (componentInfo) {
const component = findDragComponent(componentInfo)
if (component.component === 'VQuery') {
component.style.top = 0
component.style.left = 0
component.id = guid()
component.category = 'hidden'
component.commonBackground.backgroundColor = 'rgba(41, 41, 41, 1)'
changeComponentSizeWithScale(component)
dvMainStore.addComponent({ component: component, index: undefined })
adaptCurThemeCommonStyle(component)
snapshotStore.recordSnapshotCache('renderChart', component.id)
} else {
ElMessage.error('及支持添加查询组件')
}
}
}
}
const handleDragEnd = () => {
areaActive.value = false
}
const customPopStyle = computed(() => {
return {
width: '100%',
height: '100%'
}
})
const popCanvasStyle = computed(() => {
if (canvasState.value.curPointArea === 'hidden') {
let queryCount = 0
popComponentData.value.forEach(popItem => {
queryCount = 0 + popItem.propValue.length
})
return {
height: queryCount < 8 ? '15%' : (queryCount * 45 * scale.value) / 4 + 'px'
}
} else {
return { height: '0px!important', overflow: 'hidden', border: '0!important' }
}
})
onMounted(() => {
eventBus.on('handleDragEnd-canvas-main', handleDragEnd)
})
onBeforeUnmount(() => {
eventBus.off('handleDragEnd-canvas-main', handleDragEnd)
})
</script>
<style lang="less" scoped>
.pop-area {
position: absolute;
width: 100%;
max-height: 50%;
top: 0;
left: 0;
border: 1px dashed rgba(67, 67, 67, 1);
background: rgba(26, 26, 26, 1);
transition: height 0.2s ease;
z-index: 1;
}
.pop-area-main {
display: flex;
width: 100%;
justify-content: center;
align-items: center;
color: rgba(166, 166, 166, 1);
top: 0;
left: 0;
}
.pop-area-active {
border: 1px dashed rgba(51, 112, 255, 1) !important;
background: #1d2331 !important;
}
.pop-content {
position: static !important;
width: 100%;
height: 100%;
:deep(.no-list-label .container .ed-button) {
font-size: 32px;
}
:deep(.no-list-label .container) {
font-size: 32px;
}
}
</style>

View File

@ -178,7 +178,7 @@ const showTypeError = computed(() => {
})
const showDatasetError = computed(() => {
if (!curComponent.value) return false
if (!curComponent.value || curComponent.value.displayType !== '9') return false
if (!curComponent.value.checkedFields?.length) return false
if (!fields.value?.length) return false
let displayField = null

View File

@ -11,7 +11,7 @@ import {
DEFAULT_CANVAS_STYLE_DATA_DARK,
DEFAULT_CANVAS_STYLE_DATA_LIGHT,
DEFAULT_CANVAS_STYLE_DATA_SCREEN_DARK
} from '@/views/chart/components/editor/util/dataVisualiztion'
} from '@/views/chart/components/editor/util/dataVisualization'
import { useEmitt } from '@/hooks/web/useEmitt'
import chartViewManager from '@/views/chart/components/js/panel'
import {
@ -36,6 +36,9 @@ export const dvMainStore = defineStore('dataVisualization', {
chartAreaCollapse: false,
datasetAreaCollapse: false
},
canvasState: {
curPointArea: 'base' // 当前焦点所在画布区域 base 主画布区域 hidden 隐藏画布区域
},
embeddedCallBack: 'no', // 嵌入模式是否允许反馈参数
editMode: 'preview', // 编辑器模式 edit preview
mobileInPc: false,
@ -278,6 +281,18 @@ export const dvMainStore = defineStore('dataVisualization', {
}
this.curComponent = component
this.curComponentIndex = index
// 更新当前活动区域
if (this.curComponent && this.curComponent['category']) {
// 如果是图片 且图片配置了切换显示区
if (
this.curComponent.component !== 'Picture' ||
(this.curComponent.component === 'Picture' &&
(!this.curComponent.events?.checked ||
this.curComponent.events?.type !== 'displayChange'))
) {
this.canvasState['curPointArea'] = this.curComponent['category']
}
}
},
setBashMatrixInfo(bashMatrixInfo) {
this.bashMatrixInfo = bashMatrixInfo
@ -1178,6 +1193,18 @@ export const dvMainStore = defineStore('dataVisualization', {
}
}
},
popAreaActiveSwitch() {
if (this.canvasState['curPointArea'] === 'base') {
this.canvasState['curPointArea'] = 'hidden'
} else {
this.canvasState['curPointArea'] = 'base'
}
},
canvasStateChange({ key, value }) {
if (this.canvasState[key] && value) {
this.canvasState[key] = value
}
},
createInit(dvType, resourceId?, pid?, watermarkInfo?) {
const optName = dvType === 'dashboard' ? '新建仪表板' : '新建数据大屏'
this.dvInfo = {

View File

@ -3,7 +3,7 @@ import { store } from '../../index'
import { dvMainStoreWithOut } from './dvMain'
const dvMainStore = dvMainStoreWithOut()
const { curComponent } = storeToRefs(dvMainStore)
const { curComponent, componentData } = storeToRefs(dvMainStore)
export const eventStore = defineStore('event', {
actions: {
@ -13,6 +13,16 @@ export const eventStore = defineStore('event', {
removeEvent(event) {
delete curComponent.value.events[event]
},
displayEventChange(component) {
component.events.displayChange.value = !component.events.displayChange.value
dvMainStore.canvasStateChange({ key: 'curPointArea', value: area })
componentData.value.forEach(item => {
if (item.category === 'hidden') {
item.isShow = component.events.displayChange.value
}
})
}
}
})

View File

@ -2,7 +2,7 @@ import { defineStore, storeToRefs } from 'pinia'
import { store } from '../../index'
import { dvMainStoreWithOut } from './dvMain'
import { deepCopy } from '@/utils/utils'
import { BASE_THEMES } from '@/views/chart/components/editor/util/dataVisualiztion'
import { BASE_THEMES } from '@/views/chart/components/editor/util/dataVisualization'
import eventBus from '@/utils/eventBus'
import { useEmitt } from '@/hooks/web/useEmitt'
import { useCache } from '@/hooks/web/useCache'

View File

@ -33,6 +33,8 @@ import DeStreamMedia from '@/custom-component/de-stream-media/Component.vue'
import DeStreamMediaAttr from '@/custom-component/de-stream-media/Attr.vue'
import ScrollText from '@/custom-component/scroll-text/Component.vue'
import ScrollTextAttr from '@/custom-component/scroll-text/Attr.vue'
import PopArea from '@/custom-component/pop-area/Component.vue'
import PopAreaAttr from '@/custom-component/pop-area/Attr.vue'
export const componentsMap = {
VText: VText,
VQuery,
@ -68,7 +70,9 @@ export const componentsMap = {
DeStreamMedia: DeStreamMedia,
DeStreamMediaAttr: DeStreamMediaAttr,
ScrollText: ScrollText,
ScrollTextAttr: ScrollTextAttr
ScrollTextAttr: ScrollTextAttr,
PopArea: PopArea,
PopAreaAttr: PopAreaAttr
}
export default function findComponent(key) {

View File

@ -84,6 +84,7 @@ export const DEFAULT_CANVAS_STYLE_DATA_BASE = {
refreshViewLoading: true, // 仪表板图表loading提示
refreshUnit: 'minute', // 仪表板刷新时间带外 默认 分钟
refreshTime: 5, // 仪表板刷新时间 默认5分钟
popupAvailable: true, // 弹窗区域是否可用 默认为true
scale: 60,
scaleWidth: 100,
scaleHeight: 100,

View File

@ -842,8 +842,8 @@ function getTooltipPosition(event) {
return result
}
export async function exportPivotExcel(instancce: PivotSheet, chart: ChartObj) {
const { meta, fields } = instancce.dataCfg
export async function exportPivotExcel(instance: PivotSheet, chart: ChartObj) {
const { meta, fields } = instance.dataCfg
const rowLength = fields?.rows?.length || 0
const colLength = fields?.columns?.length || 0
const valueLength = fields?.values?.length || 0
@ -873,7 +873,7 @@ export async function exportPivotExcel(instancce: PivotSheet, chart: ChartObj) {
cell.value = metaMap[row]?.name ?? row
cell.alignment = { vertical: 'middle', horizontal: 'center' }
})
const { layoutResult } = instancce.facet
const { layoutResult } = instance.facet
// 行头
const { rowLeafNodes, rowsHierarchy, rowNodes } = layoutResult
const maxColIndex = rowsHierarchy.maxLevel + 1

View File

@ -78,7 +78,8 @@ const {
canvasStyleData,
canvasViewInfo,
editMode,
dvInfo
dvInfo,
canvasState
} = storeToRefs(dvMainStore)
const { editorMap } = storeToRefs(composeStore)
const canvasOut = ref(null)
@ -122,6 +123,18 @@ const handleNew = newComponentInfo => {
component.style.top = ((height - component.style.height) * scale) / 200
component.style.left = ((width - component.style.width) * scale) / 200
component.id = guid()
const popComponents = componentData.value.filter(
ele => ele.category && ele.category === 'hidden'
)
//
if (
canvasState.value.curPointArea === 'hidden' &&
component.component === 'VQuery' &&
(!popComponents || popComponents.length === 0)
) {
component.category = canvasState.value.curPointArea
component.commonBackground.backgroundColor = 'rgba(41, 41, 41, 1)'
}
changeComponentSizeWithScale(component)
dvMainStore.addComponent({ component: component, index: undefined })
adaptCurThemeCommonStyle(component)
@ -130,6 +143,7 @@ const handleNew = newComponentInfo => {
}
const handleDrop = e => {
console.log('===handleDrop2')
e.preventDefault()
e.stopPropagation()
const componentInfo = e.dataTransfer.getData('id')
@ -369,6 +383,14 @@ const scrollCanvas = e => {
deHRulerRef.value.rulerScroll(e)
}
const coreComponentData = computed(() =>
componentData.value.filter(ele => !ele.category || ele.category !== 'hidden')
)
const popComponentData = computed(() =>
componentData.value.filter(ele => ele.category && ele.category === 'hidden')
)
eventBus.on('handleNew', handleNew)
</script>
@ -389,7 +411,7 @@ eventBus.on('handleNew', handleNew)
>
<!-- 左侧组件列表 -->
<dv-sidebar
:title="'图层'"
:title="'图层管理'"
:width="180"
:scroll-width="3"
:aside-position="'left'"
@ -429,7 +451,8 @@ eventBus.on('handleNew', handleNew)
class="canvas-area-shadow editor-main"
v-if="state.canvasInitStatus"
ref="mainCanvasCoreRef"
:component-data="componentData"
:component-data="coreComponentData"
:pop-component-data="popComponentData"
:canvas-style-data="canvasStyleData"
:canvas-view-info="canvasViewInfo"
:canvas-id="state.canvasId"

View File

@ -30,7 +30,7 @@ import treeSort from '@/utils/treeSortUtils'
import {
DEFAULT_CANVAS_STYLE_DATA_LIGHT,
DEFAULT_CANVAS_STYLE_DATA_SCREEN_DARK
} from '@/views/chart/components/editor/util/dataVisualiztion'
} from '@/views/chart/components/editor/util/dataVisualization'
import type { TabPaneName } from 'element-plus-secondary'
import { timestampFormatDate } from './form/util'
import { interactiveStoreWithOut } from '@/store/modules/interactive'