Selaa lähdekoodia

fix: 修改问题

jiaxing.liao 5 tuntia sitten
vanhempi
commit
54c3cc8546

+ 1 - 1
src/renderer/src/lvgl-widgets/led/Led.vue

@@ -8,7 +8,7 @@ import { computed } from 'vue'
 const props = defineProps<{
   width: number
   height: number
-  image: string
+  image?: string
   styles: any
   part?: string
   state?: string

+ 34 - 30
src/renderer/src/views/designer/config/property/CusFormItem.vue

@@ -1,7 +1,7 @@
 <template>
   <el-col
     v-if="!schema?.hide && schema.valueType !== 'dependency'"
-    :span="schema?.componentProps?.span ?? 24"
+    :span="componentProps?.span ?? 24"
   >
     <el-form-item
       v-if="isFormItem"
@@ -18,7 +18,7 @@
         :type="schema?.slots ? 'text' : 'textarea'"
         :rows="1"
         resize="none"
-        v-bind="schema?.componentProps"
+        v-bind="componentProps"
       >
         <template #prefix>
           {{ schema?.slots?.prefix }}
@@ -33,7 +33,7 @@
         v-model="value"
         controls-position="right"
         style="width: 100%"
-        v-bind="schema?.componentProps"
+        v-bind="componentProps"
       >
         <template #prefix>
           {{ schema?.slots?.prefix }}
@@ -45,9 +45,9 @@
       <!-- 选择框 -->
       <el-select-v2
         v-if="schema.valueType === 'select'"
-        :options="schema?.componentProps?.options || []"
+        :options="componentProps?.options || []"
         v-model="value"
-        v-bind="schema?.componentProps"
+        v-bind="componentProps"
       >
         <template #prefix>
           {{ schema?.slots?.prefix }}
@@ -58,12 +58,12 @@
       </el-select-v2>
       <!-- 开关 -->
       <div v-if="schema.valueType === 'switch'" class="w-full flex justify-end">
-        <el-switch v-model="value" v-bind="schema?.componentProps" />
+        <el-switch v-model="value" v-bind="componentProps" />
       </div>
 
       <!-- 滑动条 -->
       <div v-if="schema.valueType === 'slider'" class="w-full flex gap-20px items-center">
-        <el-slider v-model="value" v-bind="schema?.componentProps" style="flex: 1"></el-slider>
+        <el-slider v-model="value" v-bind="componentProps" style="flex: 1"></el-slider>
         <span class="text-text-active inline w-30px cursor-pointer">
           {{ value }}
         </span>
@@ -72,25 +72,25 @@
       <CusTextarea
         v-if="schema.valueType === 'textarea'"
         v-model="value"
-        v-bind="schema?.componentProps"
+        v-bind="componentProps"
       />
       <!-- 图片选择 -->
       <ImageSelect
         v-if="schema.valueType === 'image'"
         v-model="value"
-        v-bind="schema?.componentProps"
+        v-bind="componentProps"
       />
       <!-- 文件选择 -->
       <FileSelect
         v-if="schema.valueType === 'file'"
         v-model="value"
-        v-bind="schema?.componentProps"
+        v-bind="componentProps"
       />
       <!-- 图标选择 -->
       <SymbolSelect
         v-if="schema.valueType === 'symbol'"
         v-model="value"
-        v-bind="schema?.componentProps"
+        v-bind="componentProps"
       />
       <!-- 颜色选择 -->
       <div class="flex" v-if="schema.valueType === 'color'">
@@ -99,7 +99,7 @@
           use-type="pure"
           picker-type="chrome"
           format="hex8"
-          v-bind="schema?.componentProps"
+          v-bind="componentProps"
         />
         <span class="text-text-active">{{ value }}</span>
       </div>
@@ -109,7 +109,7 @@
         v-if="schema.valueType === 'code'"
         class="w-full relative border border-solid border-border rounded-4px overflow-hidden"
       >
-        <MonacoEditor v-model="value" v-bind="schema?.componentProps" />
+        <MonacoEditor v-model="value" v-bind="componentProps" />
       </div>
 
       <!-- 日期 -->
@@ -117,7 +117,7 @@
         v-if="schema.valueType === 'date'"
         v-model="value"
         style="width: 100%"
-        v-bind="schema?.componentProps"
+        v-bind="componentProps"
       />
 
       <!-- 时间 -->
@@ -125,14 +125,14 @@
         v-if="schema.valueType === 'time'"
         v-model="value"
         style="width: 100%"
-        v-bind="schema?.componentProps"
+        v-bind="componentProps"
       />
     </el-form-item>
 
     <!-- 分组 -->
     <el-collapse
       v-if="!isFormItem && !schema?.render && !isStyle && schema.field !== 'part'"
-      :model-value="schema.componentProps?.defaultCollapsed ? [] : [key]"
+      :model-value="componentProps?.defaultCollapsed ? [] : [key]"
     >
       <el-collapse-item :title="schema.label" :name="key" style="margin-bottom: 12px">
         <el-card body-class="p-4px! pt-12px!" class="mb-8px!">
@@ -146,7 +146,7 @@
             <!-- 平铺多选 -->
             <CusCheckbox
               v-if="schema.valueType === 'checkbox'"
-              :options="schema?.componentProps?.options"
+              :options="componentProps?.options"
               v-model="value"
             />
           </el-row>
@@ -177,79 +177,79 @@
         <StyleBackground
           v-if="schema.valueType === 'background'"
           v-model="value"
-          v-bind="schema?.componentProps"
+          v-bind="componentProps"
         />
         <!-- 边框 -->
         <StyleBorder
           v-if="schema.valueType === 'border'"
           v-model="value"
-          v-bind="schema?.componentProps"
+          v-bind="componentProps"
         />
         <!-- 字体 -->
         <StyleFont
           v-if="schema.valueType === 'font'"
           v-model="value"
-          v-bind="schema?.componentProps"
+          v-bind="componentProps"
         />
         <!-- 外边距 -->
         <StyleMargin
           v-if="schema.valueType === 'margin'"
           v-model="value"
-          v-bind="schema?.componentProps"
+          v-bind="componentProps"
         />
         <!-- 内边距 -->
         <StylePadding
           v-if="schema.valueType === 'padding'"
           v-model="value"
-          v-bind="schema?.componentProps"
+          v-bind="componentProps"
         />
         <!-- 阴影 -->
         <StyleShadow
           v-if="schema.valueType === 'shadow'"
           v-model="value"
-          v-bind="schema?.componentProps"
+          v-bind="componentProps"
         />
         <!-- 间距 -->
         <StyleSpace
           v-if="schema.valueType === 'spacer'"
           v-model="value"
-          v-bind="schema?.componentProps"
+          v-bind="componentProps"
         />
         <!-- 线段  -->
         <StyleLine
           v-if="schema.valueType === 'line'"
           v-model="value"
-          v-bind="schema?.componentProps"
+          v-bind="componentProps"
         />
         <!-- 外边框 -->
         <StyleOutline
           v-if="schema.valueType === 'outline'"
           v-model="value"
-          v-bind="schema?.componentProps"
+          v-bind="componentProps"
         />
         <!-- 图像样式 -->
         <StyleImage
           v-if="schema.valueType === 'imageStyle'"
           v-model="value"
-          v-bind="schema?.componentProps"
+          v-bind="componentProps"
         />
         <!-- 变换样式 -->
         <StyleTransform
           v-if="schema.valueType === 'transform'"
           v-model="value"
-          v-bind="schema?.componentProps"
+          v-bind="componentProps"
         />
         <!-- 动画样式 -->
         <StyleAnimation
           v-if="schema.valueType === 'animation'"
           v-model="value"
-          v-bind="schema?.componentProps"
+          v-bind="componentProps"
         />
         <!-- 其他 -->
         <StyleOther
           v-if="schema.valueType === 'other'"
           v-model="value"
-          v-bind="schema?.componentProps"
+          v-bind="componentProps"
         />
       </template>
     </el-card>
@@ -314,6 +314,10 @@ const props = defineProps<{
   widgetData?: Record<string, any>
 }>()
 const key = v4()
+const componentProps = computed(() => {
+  const { onValueChange: _onValueChange, ...rest } = props.schema?.componentProps || {}
+  return rest
+})
 
 // 绑定数据
 const value = computed({

+ 13 - 5
src/renderer/src/views/designer/config/property/index.vue

@@ -1,5 +1,5 @@
 <template>
-  <el-scrollbar ref="scrollbarRef" height="calc(100vh - 130px)">
+  <div ref="scrollContainerRef" class="property-scroll">
     <!-- 基础属性 -->
     <el-form
       ref="formRef"
@@ -91,7 +91,7 @@
         </el-form>
       </el-collapse-item>
     </el-collapse>
-  </el-scrollbar>
+  </div>
 </template>
 
 <script setup lang="ts">
@@ -101,7 +101,6 @@ import { useProjectStore } from '@/store/modules/project'
 import componentMap from '@/lvgl-widgets'
 import StylePart from './components/StylePart.vue'
 
-import type { ScrollbarInstance } from 'element-plus'
 import { LuSliders } from 'vue-icons-plus/lu'
 import { IoColorPaletteOutline } from 'vue-icons-plus/io'
 import { klona } from 'klona'
@@ -109,7 +108,7 @@ import { assign, get } from 'lodash-es'
 
 const projectStore = useProjectStore()
 const activeKeys = ref<string[]>(['props', 'style'])
-const scrollbarRef = ref<ScrollbarInstance>()
+const scrollContainerRef = ref<HTMLDivElement>()
 const part = ref<{
   name: string
   state: string
@@ -149,7 +148,9 @@ watch(
       part.value.state = first.part.state
       part.value.expandStyle = true
     }
-    scrollbarRef.value?.scrollTo(0, 0)
+    scrollContainerRef.value?.scrollTo({
+      top: 0
+    })
   },
   {
     immediate: true
@@ -252,6 +253,13 @@ const onChangeStyleByState = (type: 'add' | 'delete') => {
 </script>
 
 <style scoped>
+.property-scroll {
+  height: calc(100vh - 130px);
+  overflow: auto;
+  overscroll-behavior: contain;
+  contain: layout paint;
+}
+
 ::v-deep(.el-collapse-icon-position-right .el-collapse-item__header) {
   padding: 0 8px;
   box-sizing: border-box;

+ 14 - 4
src/renderer/src/views/designer/workspace/stage/Moveable.vue

@@ -1,9 +1,10 @@
 <template>
   <Moveable
     v-if="pageId && pageId === projectStore.activePageId"
-    :target="elements"
+    :target="moveableTarget"
     :draggable="true"
     :resizable="true"
+    :groupable="isGroupSelection"
     :rotatable="false"
     :padding="2"
     :container="rootContainer"
@@ -36,8 +37,8 @@
     :controlPadding="4"
     :linePadding="10"
     :edge="true"
-    :individualGroupable="true"
-    :individualGroupableProps="individualGroupableProps"
+    :individualGroupable="isIndividualGroupable"
+    :individualGroupableProps="isIndividualGroupable ? individualGroupableProps : undefined"
     @render="onRender"
     @drag="onDrag"
     @resize="onResize"
@@ -76,6 +77,15 @@ const pageEl = inject<HTMLElement>('pageEl')
 const elements = ref<HTMLElement[]>([])
 const projectStore = useProjectStore()
 const appStore = useAppStore()
+const isGroupSelection = computed(() => elements.value.length > 1)
+const isIndividualGroupable = computed(() => elements.value.length === 1)
+const moveableTarget = computed<HTMLElement | HTMLElement[] | null>(() => {
+  if (isGroupSelection.value) {
+    return elements.value
+  }
+
+  return elements.value[0] ?? null
+})
 
 // 吸附附近元素
 const elementGridelines = ref<Element[]>([])
@@ -333,7 +343,7 @@ const onRotateEnd = (e) => {
   const id = e.target.attributes['widget-id']?.value
   if (e.lastEvent && id && projectStore.activeWidgetMap[id]) {
     // 设置位置
-    projectStore.activeWidgetMap[id].props.rotate.angle = Math.round(e.lastEvent.rotate)
+    projectStore.activeWidgetMap[id].props.rotation = Math.round(e.lastEvent.rotate)
   }
 }
 </script>

+ 37 - 11
src/renderer/src/views/designer/workspace/stage/Node.vue

@@ -49,8 +49,8 @@ import type { Page } from '@/types/page'
 import type { StageState } from './type'
 import type { CSSProperties } from 'vue'
 
-import { computed, ref, inject, watch, nextTick } from 'vue'
-import { useDrop, useMouse, useEventListener } from 'vue-hooks-plus'
+import { computed, ref, inject, watch, nextTick, onBeforeUnmount } from 'vue'
+import { useDrop, useMouse } from 'vue-hooks-plus'
 import { createWidget } from '@/model'
 import LvglWidgets from '@/lvgl-widgets'
 import { useProjectStore } from '@/store/modules/project'
@@ -293,6 +293,36 @@ const nodeState = useMouse(nodeRef)
 let dropFlag = false
 let offsetX = 0
 let offsetY = 0
+let mouseupTarget: Element | null = null
+
+const handleDropMouseup = (e: Event) => {
+  const mouseEvent = e as MouseEvent
+  offsetX = mouseEvent.offsetX
+  offsetY = mouseEvent.offsetY
+  mouseupTarget = null
+}
+
+const clearDropMouseupListener = () => {
+  if (!mouseupTarget) return
+
+  mouseupTarget.removeEventListener('mouseup', handleDropMouseup, true)
+  mouseupTarget = null
+}
+
+const bindDropMouseupListener = (target?: Element) => {
+  if (!target || mouseupTarget === target) return
+
+  clearDropMouseupListener()
+  mouseupTarget = target
+  target.addEventListener('mouseup', handleDropMouseup, {
+    once: true,
+    capture: true
+  })
+}
+
+onBeforeUnmount(() => {
+  clearDropMouseupListener()
+})
 
 watch(nodeState, (state) => {
   const { schema } = props
@@ -302,6 +332,7 @@ watch(nodeState, (state) => {
     // 停止拖拽且允许放置时剪切到容器内
     if (dropFlag && !appStore.draging) {
       dropFlag = false
+      clearDropMouseupListener()
       // 放置到容器内
       // 获取在容器的真实位置
       const scale = elementW / schema.props.width
@@ -343,7 +374,7 @@ watch(nodeState, (state) => {
       // 获取当前鼠标位置全部控件节点元素
       const elements = document
         .elementsFromPoint(clientX, clientY)
-        ?.filter((el) => el.className.includes('widget-node'))
+        ?.filter((el) => el.className?.includes?.('widget-node'))
       // 获取第一个元素不是自身的元素
       const targetEl = elements.find((el) => {
         const id = el.attributes.getNamedItem('widget-id')?.value
@@ -358,21 +389,16 @@ watch(nodeState, (state) => {
           boxShadow: '0px 0px 10px #00fcfc'
         }
         dropFlag = true
-        useEventListener(
-          'mouseup',
-          (e: MouseEvent) => {
-            offsetX = e.offsetX
-            offsetY = e.offsetY
-          },
-          { once: true, capture: true, target: elements[0] }
-        )
+        bindDropMouseupListener(elements[0])
       } else if (!isEmpty(dropStyle.value)) {
         dropFlag = false
+        clearDropMouseupListener()
         // 容器外
         dropStyle.value = {}
       }
     } else if (!isEmpty(dropStyle.value)) {
       dropFlag = false
+      clearDropMouseupListener()
       // 容器外
       dropStyle.value = {}
     }