Bladeren bron

fix: 修改画布节点拖拽到容器

jiaxing.liao 2 weken geleden
bovenliggende
commit
b572c47351

+ 4 - 1
src/renderer/index.html

@@ -17,8 +17,11 @@
       #app {
         width: 100vw;
         height: 100vh;
-        user-select: none;
         font-size: 12px;
+        -webkit-user-select: none;
+        -moz-user-select: none;
+        -ms-user-select: none;
+        user-select: none;
       }
     </style>
   </head>

+ 1 - 1
src/renderer/src/lvgl-widgets/container/Container.vue

@@ -1,5 +1,5 @@
 <template>
-  <div :style="styleMap?.mainStyle"></div>
+  <div :style="styleMap?.mainStyle" class="box-border"></div>
 </template>
 
 <script setup lang="ts">

+ 1 - 1
src/renderer/src/lvgl-widgets/container/index.ts

@@ -6,7 +6,7 @@ import i18n from '@/locales'
 import defaultStyle from './style.json'
 
 export default {
-  label: i18n.global.t('layout'),
+  label: i18n.global.t('container'),
   icon,
   component: Container,
   key: 'lv_obj',

+ 8 - 5
src/renderer/src/store/modules/action.ts

@@ -229,11 +229,13 @@ export const useActionStore = defineStore('action', () => {
    */
   const onDeleteById = (widgetId: string) => {
     projectStore.project?.screens.forEach((screen) => {
-      bfsWalk(screen.pages, (child) => {
-        const index = child?.children?.findIndex((item) => item.id === widgetId) ?? -1
-        if (index !== -1) {
-          child.children.splice(index, 1)
-        }
+      screen.pages.forEach((page) => {
+        bfsWalk(page, (child) => {
+          const index = child?.children?.findIndex((item) => item.id === widgetId) ?? -1
+          if (index !== -1) {
+            child.children.splice(index, 1)
+          }
+        })
       })
     })
   }
@@ -497,6 +499,7 @@ export const useActionStore = defineStore('action', () => {
     debounce((e: KeyboardEvent) => {
       // 忽略输入框
       if ((e.target as HTMLElement)?.className.includes('el-')) return
+
       onSelectAll()
     }, 100)
   )

+ 93 - 3
src/renderer/src/views/designer/workspace/stage/Node.vue

@@ -40,15 +40,18 @@ import type { Page } from '@/types/page'
 import type { StageState } from './type'
 import type { CSSProperties } from 'vue'
 
-import { computed, ref, inject } from 'vue'
-import { useDrop } from 'vue-hooks-plus'
+import { computed, ref, inject, watch } from 'vue'
+import { useDrop, useMouse, useEventListener } from 'vue-hooks-plus'
 import { createWidget } from '@/model'
 import LvglWidgets from '@/lvgl-widgets'
 import { useProjectStore } from '@/store/modules/project'
-import { has } from 'lodash-es'
+import { useAppStore } from '@/store/modules/app'
+import { useActionStore } from '@/store/modules/action'
+import { has, isEmpty } from 'lodash-es'
 
 import ContentMenu from './ContentMenu.vue'
 import { getAddWidgetIndex } from '@/utils'
+import { klona } from 'klona'
 
 defineOptions({
   name: 'NodeItem'
@@ -69,6 +72,8 @@ const props = defineProps<{
 }>()
 
 const projectStore = useProjectStore()
+const appStore = useAppStore()
+const actionStore = useActionStore()
 // 获取lvgl vue控件
 const widget = computed(() => LvglWidgets[props.schema.type]?.component)
 // 节点容器放置ref
@@ -176,6 +181,91 @@ useDrop(nodeRef, {
   }
 })
 
+// 监听鼠标位置
+const nodeState = useMouse(nodeRef)
+// 可放置标识
+let dropFlag = false
+let offsetX = 0
+let offsetY = 0
+
+watch(nodeState, (state) => {
+  if (props.schema?.children && props.schema.type !== 'page') {
+    const { elementW, elementH, elementX, elementY, clientX, clientY } = state
+
+    // 停止拖拽且允许放置时剪切到容器内
+    if (dropFlag && !appStore.draging) {
+      dropFlag = false
+      // 放置到容器内
+      // 获取在容器的真实位置
+      const scale = elementW / props.schema.props.width
+      const x = elementX / scale - offsetX
+      const y = elementY / scale - offsetY
+
+      projectStore.activeWidgets[0].props.x = x
+      projectStore.activeWidgets[0].props.y = y
+
+      const node = klona(projectStore.activeWidgets[0])
+      // 删除原来的节点
+      actionStore.onDeleteById(node.id)
+      props.schema.children.unshift(node)
+      projectStore.activeWidgets = [node]
+    }
+    // 鼠标在节点内部
+    // 处于节点拖拽状态
+    // 当前选中节点只有一个
+    // 且非自身节点
+    // 非自身子节点
+    // 非页面节点
+    if (
+      elementX > 0 &&
+      elementX < elementW &&
+      elementY > 0 &&
+      elementY < elementH &&
+      appStore.draging &&
+      projectStore.activeWidgets.length === 1 &&
+      projectStore.activeWidgets[0].id !== props.schema.id &&
+      props.schema.children.every((item) => item.id !== projectStore.activeWidgets[0].id) &&
+      props.schema.type !== 'page'
+    ) {
+      // 获取当前鼠标位置全部控件节点元素
+      const elements = document
+        .elementsFromPoint(clientX, clientY)
+        ?.filter((el) => el.className.includes('widget-node'))
+      // 获取第一个元素不是自身的元素
+      const targetEl = elements.find((el) => {
+        const id = el.attributes.getNamedItem('widget-id')?.value
+        return id !== projectStore.activeWidget?.id
+      })
+      const targetId = targetEl?.attributes.getNamedItem('widget-id')?.value
+
+      if (targetId === props.schema.id) {
+        // 最上层的容器
+        dropStyle.value = {
+          // 放置阴影效果
+          boxShadow: '0px 0px 10px #00fcfc'
+        }
+        dropFlag = true
+        useEventListener(
+          'mouseup',
+          (e: MouseEvent) => {
+            offsetX = e.offsetX
+            offsetY = e.offsetY
+          },
+          { once: true, capture: true, target: elements[0] }
+        )
+      } else if (!isEmpty(dropStyle.value)) {
+        dropFlag = false
+        // 容器外
+        dropStyle.value = {}
+      }
+    } else if (!isEmpty(dropStyle.value)) {
+      dropFlag = false
+      // 容器外
+      dropStyle.value = {}
+    }
+  }
+})
+
 // 选择节点
 const handleSelect = (e: MouseEvent) => {
   if (props.schema.type !== 'page') {