|
@@ -40,15 +40,18 @@ import type { Page } from '@/types/page'
|
|
|
import type { StageState } from './type'
|
|
import type { StageState } from './type'
|
|
|
import type { CSSProperties } from 'vue'
|
|
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 { createWidget } from '@/model'
|
|
|
import LvglWidgets from '@/lvgl-widgets'
|
|
import LvglWidgets from '@/lvgl-widgets'
|
|
|
import { useProjectStore } from '@/store/modules/project'
|
|
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 ContentMenu from './ContentMenu.vue'
|
|
|
import { getAddWidgetIndex } from '@/utils'
|
|
import { getAddWidgetIndex } from '@/utils'
|
|
|
|
|
+import { klona } from 'klona'
|
|
|
|
|
|
|
|
defineOptions({
|
|
defineOptions({
|
|
|
name: 'NodeItem'
|
|
name: 'NodeItem'
|
|
@@ -69,6 +72,8 @@ const props = defineProps<{
|
|
|
}>()
|
|
}>()
|
|
|
|
|
|
|
|
const projectStore = useProjectStore()
|
|
const projectStore = useProjectStore()
|
|
|
|
|
+const appStore = useAppStore()
|
|
|
|
|
+const actionStore = useActionStore()
|
|
|
// 获取lvgl vue控件
|
|
// 获取lvgl vue控件
|
|
|
const widget = computed(() => LvglWidgets[props.schema.type]?.component)
|
|
const widget = computed(() => LvglWidgets[props.schema.type]?.component)
|
|
|
// 节点容器放置ref
|
|
// 节点容器放置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) => {
|
|
const handleSelect = (e: MouseEvent) => {
|
|
|
if (props.schema.type !== 'page') {
|
|
if (props.schema.type !== 'page') {
|