From f3274c0528ecf2a80444fa8b07d3fc43d21f9301 Mon Sep 17 00:00:00 2001 From: wangjiahao <1522128093@qq.com> Date: Wed, 13 Dec 2023 13:29:35 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E6=95=B0=E6=8D=AE=E5=A4=A7=E5=B1=8F):=20?= =?UTF-8?q?=E7=BB=84=E5=90=88=E5=88=B0=E4=B8=80=E4=B8=AA=E5=88=86=E7=BB=84?= =?UTF-8?q?=E5=90=8E=EF=BC=8C=E5=9C=A8=E5=9B=BE=E5=B1=82=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E4=B8=AD=EF=BC=8C=E5=8F=AF=E4=BB=A5=E6=9F=A5=E7=9C=8B=E8=AF=A5?= =?UTF-8?q?=E5=88=86=E7=BB=84=E4=B8=8B=E7=9A=84=E7=BB=84=E4=BB=B6=E5=88=97?= =?UTF-8?q?=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...omponentTreeList.vue => RealTimeGroup.vue} | 52 +- .../data-visualization/RealTimeListTree.vue | 481 ++++++++++++++++++ .../src/views/data-visualization/index.vue | 3 +- 3 files changed, 500 insertions(+), 36 deletions(-) rename core/core-frontend/src/components/data-visualization/{RealTimeComponentTreeList.vue => RealTimeGroup.vue} (91%) create mode 100644 core/core-frontend/src/components/data-visualization/RealTimeListTree.vue diff --git a/core/core-frontend/src/components/data-visualization/RealTimeComponentTreeList.vue b/core/core-frontend/src/components/data-visualization/RealTimeGroup.vue similarity index 91% rename from core/core-frontend/src/components/data-visualization/RealTimeComponentTreeList.vue rename to core/core-frontend/src/components/data-visualization/RealTimeGroup.vue index 98e516e4b0..1e1ec7abf3 100644 --- a/core/core-frontend/src/components/data-visualization/RealTimeComponentTreeList.vue +++ b/core/core-frontend/src/components/data-visualization/RealTimeGroup.vue @@ -3,7 +3,7 @@ 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 { ElCol, ElIcon, ElRow } from 'element-plus-secondary' +import { ElIcon, ElRow } from 'element-plus-secondary' import Icon from '../icon-custom/src/Icon.vue' import { computed, nextTick, ref } from 'vue' import draggable from 'vuedraggable' @@ -11,7 +11,6 @@ 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 { contextmenuStoreWithOut } from '@/store/modules/data-visualization/contextmenu' const dropdownMore = ref(null) const lockStore = lockStoreWithOut() @@ -19,11 +18,13 @@ const dvMainStore = dvMainStoreWithOut() const snapshotStore = snapshotStoreWithOut() const layerStore = layerStoreWithOut() const composeStore = composeStoreWithOut() -const contextmenuStore = contextmenuStoreWithOut() const { areaData, isCtrlOrCmdDown, isShiftDown, laterIndex } = storeToRefs(composeStore) -const { componentData, curComponent, curComponentIndex, canvasViewInfo } = storeToRefs(dvMainStore) +const { curComponent, canvasViewInfo } = storeToRefs(dvMainStore) + +const componentData = computed(() => dvMainStore.componentData) + const getComponent = index => { return componentData.value[componentData.value.length - 1 - index] } @@ -87,24 +88,6 @@ const onClick = (e, index) => { setCurComponent(index) composeStore.setLaterIndex(index) } -const deleteComponent = (number: number) => { - setTimeout(() => { - dvMainStore.deleteComponentById(curComponent.value.id) - snapshotStore.recordSnapshotCache('renderChart') - }) -} -const upComponent = (number: number) => { - setTimeout(() => { - layerStore.upComponent() - snapshotStore.recordSnapshotCache() - }) -} -const downComponent = (number: number) => { - setTimeout(() => { - layerStore.downComponent() - snapshotStore.recordSnapshotCache('realTime-downComponent') - }) -} const setCurComponent = index => { dvMainStore.setCurComponent({ component: componentData.value[index], index }) } @@ -113,7 +96,9 @@ 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 @@ -126,15 +111,12 @@ const closeEditComponentName = () => { if (!inputName.value || !inputName.value.trim()) { return } - if (inputName.value.trim() === curComponent.value.name) { + if (inputName.value.trim() === curEditComponent.name) { return } - curComponent.value.name = inputName.value + curEditComponent.name = inputName.value inputName.value = '' -} - -const toggleComponentVisible = () => { - // do toggleComponentVisible + curEditComponent = null } const lock = () => { @@ -198,9 +180,6 @@ const menuAsideClose = (param, index) => { }, 200) } } -const rename = item => { - editComponentName(item) -} const handleContextMenu = e => { e.preventDefault() @@ -248,12 +227,15 @@ const handleContextMenu = e => { areaData.components.includes(getComponent(index)) }" @click="onClick($event, transformIndex(index))" - @dblclick="editComponentName(getComponent(index))" > - + {{ getComponent(index)?.name }}
{ trigger="click" placement="bottom-start" effect="dark" - hide-timeout="0" + :hide-timeout="0" > @@ -313,7 +295,7 @@ const handleContextMenu = e => { trigger="contextmenu" placement="bottom-start" effect="dark" - hide-timeout="0" + :hide-timeout="0" > +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 } 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 RealTimeGroup from '@/components/data-visualization/RealTimeGroup.vue' +const dropdownMore = ref(null) +const lockStore = lockStoreWithOut() + +const dvMainStore = dvMainStoreWithOut() +const snapshotStore = snapshotStoreWithOut() +const layerStore = layerStoreWithOut() +const composeStore = composeStoreWithOut() + +const { areaData, isCtrlOrCmdDown, isShiftDown, laterIndex } = storeToRefs(composeStore) + +const { componentData, curComponent, canvasViewInfo } = storeToRefs(dvMainStore) +const getComponent = index => { + return componentData.value[componentData.value.length - 1 - index] +} +const transformIndex = index => { + return componentData.value.length - 1 - index +} +const areaDataPush = component => { + if (component && !component.isLock && component.isShow) { + areaData.value.components.push(component) + } +} +// shift 选择算法逻辑 +// 1.记录上次点击的laterIndex(初始状态laterIndex=0); +// 2.获取当前index curClickIndex; +// 3.比较laterIndex 和 curClickIndex之间的大小; +// 4.将[laterIndex,curClickIndex] 或者 [curClickIndex,laterIndex]区域的图层加入areaData.value.components(已包含的不再重复加入); +const shiftDataPush = curClickIndex => { + const areaDataIdArray = areaData.value.components.map(com => com.id) + let indexBegin, indexEnd + const laterIndexTrans = laterIndex.value === null ? componentData.value.length : laterIndex.value + if (laterIndexTrans < curClickIndex) { + indexBegin = laterIndexTrans + indexEnd = curClickIndex + } else { + indexBegin = curClickIndex + indexEnd = laterIndexTrans + } + const shiftAreaComponents = componentData.value + .slice(indexBegin, indexEnd + 1) + .filter( + component => !areaDataIdArray.includes(component.id) && !component.isLock && component.isShow + ) + areaData.value.components.push(...shiftAreaComponents) + dvMainStore.setCurComponent({ component: null, index: null }) +} + +const onClick = (e, index) => { + // 初始化点击是 laterIndex=0 + if (!curComponent.value) { + composeStore.setLaterIndex(null) + } + // ctrl or command 按下时 鼠标点击为选择需要组合的组件(取消需要组合的组件在ComposeShow组件中) + if (isCtrlOrCmdDown.value && !areaData.value.components.includes(componentData.value[index])) { + areaDataPush(componentData.value[index]) + if (curComponent.value && curComponent.value.id !== componentData.value[index].id) { + areaDataPush(curComponent.value) + } + dvMainStore.setCurComponent({ component: null, index: null }) + e.stopPropagation() + composeStore.setLaterIndex(index) + return + } + //shift操作逻辑 + if (isShiftDown.value) { + shiftDataPush(index) + return + } + + //其他情况点击清理选择区域 + areaData.value.components.splice(0, areaData.value.components.length) + setCurComponent(index) + composeStore.setLaterIndex(index) +} +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() + }) +} + +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 getIconName = item => { + if (item.component === 'UserView') { + const viewInfo = canvasViewInfo.value[item.id] + return `${viewInfo.type}-origin` + } else { + return 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) + }) +} + + + + + + + diff --git a/core/core-frontend/src/views/data-visualization/index.vue b/core/core-frontend/src/views/data-visualization/index.vue index 960a6e282f..559c0e15bc 100644 --- a/core/core-frontend/src/views/data-visualization/index.vue +++ b/core/core-frontend/src/views/data-visualization/index.vue @@ -25,6 +25,7 @@ import { changeComponentSizeWithScale } from '@/utils/changeComponentsSizeWithSc import { useEmitt } from '@/hooks/web/useEmitt' import { check, compareStorage } from '@/utils/CrossPermission' import { useCache } from '@/hooks/web/useCache' +import RealTimeListTree from '@/components/data-visualization/RealTimeListTree.vue' const { wsCache } = useCache() const eventCheck = e => { if (e.key === 'screen-weight' && !compareStorage(e.oldValue, e.newValue)) { @@ -253,7 +254,7 @@ eventBus.on('handleNew', handleNew) id="dv-main-left-sidebar" :class="{ 'preview-aside': previewStatus }" > - +