ソースを参照

fix: 修改问题调整设置

jiaxing.liao 5 ヶ月 前
コミット
6c49b324b6
31 ファイル変更499 行追加252 行削除
  1. 64 65
      src/renderer/src/constants/index.ts
  2. 2 1
      src/renderer/src/lvgl-widgets/button-matrix/ButtonMatrix.vue
  3. 4 1
      src/renderer/src/lvgl-widgets/button-matrix/index.tsx
  4. 7 3
      src/renderer/src/lvgl-widgets/button/index.ts
  5. 4 5
      src/renderer/src/lvgl-widgets/checkbox/index.ts
  6. 13 13
      src/renderer/src/lvgl-widgets/container/index.ts
  7. 1 0
      src/renderer/src/lvgl-widgets/dropdown/Dropdown.vue
  8. 3 1
      src/renderer/src/lvgl-widgets/dropdown/index.tsx
  9. 1 0
      src/renderer/src/lvgl-widgets/image-button/ImageButton.vue
  10. 11 15
      src/renderer/src/lvgl-widgets/image-button/index.ts
  11. 3 1
      src/renderer/src/lvgl-widgets/image/index.ts
  12. 7 6
      src/renderer/src/lvgl-widgets/label/Label.vue
  13. 3 1
      src/renderer/src/lvgl-widgets/label/index.ts
  14. 2 2
      src/renderer/src/lvgl-widgets/label/style.json
  15. 7 2
      src/renderer/src/lvgl-widgets/span-group/index.tsx
  16. 3 1
      src/renderer/src/lvgl-widgets/textarea/index.ts
  17. 6 2
      src/renderer/src/lvgl-widgets/type.d.ts
  18. 5 0
      src/renderer/src/style.less
  19. 6 1
      src/renderer/src/views/designer/config/property/CusFormItem.vue
  20. 36 4
      src/renderer/src/views/designer/config/property/components/CusTextarea.vue
  21. 1 1
      src/renderer/src/views/designer/config/property/components/ImageSelect.vue
  22. 22 17
      src/renderer/src/views/designer/config/property/components/StyleBorder.vue
  23. 2 0
      src/renderer/src/views/designer/config/property/components/StyleFont.vue
  24. 5 1
      src/renderer/src/views/designer/config/property/components/StyleGap.vue
  25. 62 32
      src/renderer/src/views/designer/config/property/components/StyleMargin.vue
  26. 64 33
      src/renderer/src/views/designer/config/property/components/StylePadding.vue
  27. 68 34
      src/renderer/src/views/designer/config/property/components/StyleShadow.vue
  28. 40 0
      src/renderer/src/views/designer/config/property/components/SymbolSelectModal.vue
  29. 46 9
      src/renderer/src/views/designer/config/property/index.vue
  30. 0 1
      src/renderer/src/views/designer/workspace/stage/Moveable.vue
  31. 1 0
      src/renderer/src/views/designer/workspace/stage/Node.vue

+ 64 - 65
src/renderer/src/constants/index.ts

@@ -6,11 +6,11 @@
 export const flagOptions = [
   { label: 'Hidden', value: 'LV_OBJ_FLAG_HIDDEN' },
   { label: 'Clickable', value: 'LV_OBJ_FLAG_CLICKABLE' },
-  { label: 'Focusable', value: 'LV_OBJ_FLAG_CLICK_FOCUSABLE' },
+  { label: 'Click Focusable', value: 'LV_OBJ_FLAG_CLICK_FOCUSABLE' },
   { label: 'Checkable', value: 'LV_OBJ_FLAG_CHECKABLE' },
   { label: 'Scrollable', value: 'LV_OBJ_FLAG_SCROLLABLE' },
   { label: 'Scroll Elastic', value: 'LV_OBJ_FLAG_SCROLL_ELASTIC' },
-  { label: 'Scroll momentun', value: 'LV_OBJ_FLAG_SCROLL_MOMENTUM' },
+  { label: 'Scroll Momentum', value: 'LV_OBJ_FLAG_SCROLL_MOMENTUM' },
   { label: 'Scroll One', value: 'LV_OBJ_FLAG_SCROLL_ONE' },
   { label: 'Scroll Chain Hor', value: 'LV_OBJ_FLAG_SCROLL_CHAIN_HOR' },
   { label: 'Scroll Chain Ver', value: 'LV_OBJ_FLAG_SCROLL_CHAIN_VER' },
@@ -23,8 +23,8 @@ export const flagOptions = [
   { label: 'Gesture Bubble', value: 'LV_OBJ_FLAG_GESTURE_BUBBLE' },
   { label: 'Adv Hittest', value: 'LV_OBJ_FLAG_ADV_HITTEST' },
   { label: 'Ignore Layout', value: 'LV_OBJ_FLAG_IGNORE_LAYOUT' },
-  { label: 'floating', value: 'LV_OBJ_FLAG_FLOATING' },
-  { label: 'Send Draw Task Events', value: 'LV_OBJ_FLAG_SEND_DRAW_TASK_EVENTS' },
+  { label: 'Floating', value: 'LV_OBJ_FLAG_FLOATING' },
+  // { label: 'Send Draw Task Events', value: 'LV_OBJ_FLAG_SEND_DRAW_TASK_EVENTS' },
   { label: 'Overflow Visible', value: 'LV_OBJ_FLAG_OVERFLOW_VISIBLE' }
   // { label: 'Event Trickle', value: 'LV_OBJ_FLAG_EVENT_TRICKLE' },
   // { label: 'State Trickle', value: 'LV_OBJ_FLAG_STATE_TRICKLE' },
@@ -160,67 +160,66 @@ export const scrollbarModes = [
  * Symbol符号
  */
 export const symbols = [
-  { label: 'LV_SYMBOL_AUDIO', value: '\xEF\x80\x81' },
-  { label: 'LV_SYMBOL_VIDEO', value: '\xEF\x80\x88' },
-  { label: 'LV_SYMBOL_LIST', value: '\xEF\x80\x8B' },
-  { label: 'LV_SYMBOL_OK', value: '\xEF\x80\x8C' },
-  { label: 'LV_SYMBOL_CLOSE', value: '\xEF\x80\x8D' },
-  { label: 'LV_SYMBOL_POWER', value: '\xEF\x80\x91' },
-  { label: 'LV_SYMBOL_SETTINGS', value: '\xEF\x80\x93' },
-  { label: 'LV_SYMBOL_HOME', value: '\xEF\x80\x95' },
-  { label: 'LV_SYMBOL_DOWNLOAD', value: '\xEF\x80\x99' },
-  { label: 'LV_SYMBOL_DRIVE', value: '\xEF\x80\x9C' },
-  { label: 'LV_SYMBOL_REFRESH', value: '\xEF\x80\xA1' },
-  { label: 'LV_SYMBOL_MUTE', value: '\xEF\x80\xA6' },
-  { label: 'LV_SYMBOL_VOLUME_MID', value: '\xEF\x80\xA7' },
-  { label: 'LV_SYMBOL_VOLUME_MAX', value: '\xEF\x80\xA8' },
-  { label: 'LV_SYMBOL_IMAGE', value: '\xEF\x80\xBE' },
-  { label: 'LV_SYMBOL_TINT', value: '\xEF\x81\x83' },
-  { label: 'LV_SYMBOL_PREV', value: '\xEF\x81\x88' },
-  { label: 'LV_SYMBOL_PLAY', value: '\xEF\x81\x8B' },
-  { label: 'LV_SYMBOL_PAUSE', value: '\xEF\x81\x8C' },
-  { label: 'LV_SYMBOL_STOP', value: '\xEF\x81\x8D' },
-  { label: 'LV_SYMBOL_NEXT', value: '\xEF\x81\x91' },
-  { label: 'LV_SYMBOL_EJECT', value: '\xEF\x81\x92' },
-  { label: 'LV_SYMBOL_LEFT', value: '\xEF\x81\x93' },
-  { label: 'LV_SYMBOL_RIGHT', value: '\xEF\x81\x94' },
-  { label: 'LV_SYMBOL_PLUS', value: '\xEF\x81\xA7' },
-  { label: 'LV_SYMBOL_MINUS', value: '\xEF\x81\xA8' },
-  { label: 'LV_SYMBOL_EYE_OPEN', value: '\xEF\x81\xAE' },
-  { label: 'LV_SYMBOL_EYE_CLOSE', value: '\xEF\x81\xB0' },
-  { label: 'LV_SYMBOL_WARNING', value: '\xEF\x81\xB1' },
-  { label: 'LV_SYMBOL_SHUFFLE', value: '\xEF\x81\xB4' },
-  { label: 'LV_SYMBOL_UP', value: '\xEF\x81\xB7' },
-  { label: 'LV_SYMBOL_DOWN', value: '\xEF\x81\xB8' },
-  { label: 'LV_SYMBOL_LOOP', value: '\xEF\x81\xB9' },
-  { label: 'LV_SYMBOL_DIRECTORY', value: '\xEF\x81\xBB' },
-  { label: 'LV_SYMBOL_UPLOAD', value: '\xEF\x82\x93' },
-  { label: 'LV_SYMBOL_CALL', value: '\xEF\x82\x95' },
-  { label: 'LV_SYMBOL_CUT', value: '\xEF\x83\x84' },
-  { label: 'LV_SYMBOL_COPY', value: '\xEF\x83\x85' },
-  { label: 'LV_SYMBOL_SAVE', value: '\xEF\x83\x87' },
-  { label: 'LV_SYMBOL_BARS', value: '\xEF\x83\x89' },
-  { label: 'LV_SYMBOL_ENVELOPE', value: '\xEF\x83\xA0' },
-  { label: 'LV_SYMBOL_CHARGE', value: '\xEF\x83\xA7' },
-  { label: 'LV_SYMBOL_PASTE', value: '\xEF\x83\xAA' },
-  { label: 'LV_SYMBOL_BELL', value: '\xEF\x83\xB3' },
-  { label: 'LV_SYMBOL_KEYBOARD', value: '\xEF\x84\x9C' },
-  { label: 'LV_SYMBOL_GPS', value: '\xEF\x84\xA4' },
-  { label: 'LV_SYMBOL_FILE', value: '\xEF\x85\x9B' },
-  { label: 'LV_SYMBOL_WIFI', value: '\xEF\x87\xAB' },
-  { label: 'LV_SYMBOL_BATTERY_FULL', value: '\xEF\x89\x80' },
-  { label: 'LV_SYMBOL_BATTERY_3', value: '\xEF\x89\x81' },
-  { label: 'LV_SYMBOL_BATTERY_2', value: '\xEF\x89\x82' },
-  { label: 'LV_SYMBOL_BATTERY_1', value: '\xEF\x89\x83' },
-  { label: 'LV_SYMBOL_BATTERY_EMPTY', value: '\xEF\x89\x84' },
-  { label: 'LV_SYMBOL_USB', value: '\xEF\x8a\x87' },
-  { label: 'LV_SYMBOL_BLUETOOTH', value: '\xEF\x8a\x93' },
-  { label: 'LV_SYMBOL_TRASH', value: '\xEF\x8B\xAD' },
-  { label: 'LV_SYMBOL_EDIT', value: '\xEF\x8C\x84' },
-  { label: 'LV_SYMBOL_BACKSPACE', value: '\xEF\x95\x9A' },
-  { label: 'LV_SYMBOL_SD_CARD', value: '\xEF\x9F\x82' },
-  { label: 'LV_SYMBOL_NEW_LINE', value: '\xEF\xA2\xA2' },
-  { label: 'LV_SYMBOL_DUMMY', value: '\xEF\xA3\xBF' }
+  { label: 'LV_SYMBOL_AUDIO', value: '' },
+  { label: 'LV_SYMBOL_VIDEO', value: '' },
+  { label: 'LV_SYMBOL_LIST', value: '' },
+  { label: 'LV_SYMBOL_OK', value: '' },
+  { label: 'LV_SYMBOL_CLOSE', value: '' },
+  { label: 'LV_SYMBOL_POWER', value: '' },
+  { label: 'LV_SYMBOL_SETTINGS', value: '' },
+  { label: 'LV_SYMBOL_HOME', value: '' },
+  { label: 'LV_SYMBOL_DOWNLOAD', value: '' },
+  { label: 'LV_SYMBOL_DRIVE', value: '' },
+  { label: 'LV_SYMBOL_REFRESH', value: '' },
+  { label: 'LV_SYMBOL_MUTE', value: '' },
+  { label: 'LV_SYMBOL_VOLUME_MID', value: '' },
+  { label: 'LV_SYMBOL_VOLUME_MAX', value: '' },
+  { label: 'LV_SYMBOL_IMAGE', value: '' },
+  { label: 'LV_SYMBOL_TINT', value: '' },
+  { label: 'LV_SYMBOL_PREV', value: '' },
+  { label: 'LV_SYMBOL_PLAY', value: '' },
+  { label: 'LV_SYMBOL_PAUSE', value: '' },
+  { label: 'LV_SYMBOL_STOP', value: '' },
+  { label: 'LV_SYMBOL_NEXT', value: '' },
+  { label: 'LV_SYMBOL_EJECT', value: '' },
+  { label: 'LV_SYMBOL_LEFT', value: '' },
+  { label: 'LV_SYMBOL_RIGHT', value: '' },
+  { label: 'LV_SYMBOL_PLUS', value: '' },
+  { label: 'LV_SYMBOL_MINUS', value: '' },
+  { label: 'LV_SYMBOL_EYE_OPEN', value: '' },
+  { label: 'LV_SYMBOL_EYE_CLOSE', value: '' },
+  { label: 'LV_SYMBOL_WARNING', value: '' },
+  { label: 'LV_SYMBOL_SHUFFLE', value: '' },
+  { label: 'LV_SYMBOL_UP', value: '' },
+  { label: 'LV_SYMBOL_DOWN', value: '' },
+  { label: 'LV_SYMBOL_LOOP', value: '' },
+  { label: 'LV_SYMBOL_DIRECTORY', value: '' },
+  { label: 'LV_SYMBOL_UPLOAD', value: '' },
+  { label: 'LV_SYMBOL_CALL', value: '' },
+  { label: 'LV_SYMBOL_CUT', value: '' },
+  { label: 'LV_SYMBOL_COPY', value: '' },
+  { label: 'LV_SYMBOL_SAVE', value: '' },
+  { label: 'LV_SYMBOL_BARS', value: '' },
+  { label: 'LV_SYMBOL_ENVELOPE', value: '' },
+  { label: 'LV_SYMBOL_CHARGE', value: '' },
+  { label: 'LV_SYMBOL_PASTE', value: '' },
+  { label: 'LV_SYMBOL_BELL', value: '' },
+  { label: 'LV_SYMBOL_KEYBOARD', value: '' },
+  { label: 'LV_SYMBOL_GPS', value: '' },
+  { label: 'LV_SYMBOL_FILE', value: '' },
+  { label: 'LV_SYMBOL_WIFI', value: '' },
+  { label: 'LV_SYMBOL_BATTERY_FULL', value: '' },
+  { label: 'LV_SYMBOL_BATTERY_3', value: '' },
+  { label: 'LV_SYMBOL_BATTERY_2', value: '' },
+  { label: 'LV_SYMBOL_BATTERY_1', value: '' },
+  { label: 'LV_SYMBOL_BATTERY_EMPTY', value: '' },
+  { label: 'LV_SYMBOL_USB', value: '' },
+  { label: 'LV_SYMBOL_BLUETOOTH', value: '' },
+  { label: 'LV_SYMBOL_TRASH', value: '' },
+  { label: 'LV_SYMBOL_EDIT', value: '' },
+  { label: 'LV_SYMBOL_BACKSPACE', value: '' },
+  { label: 'LV_SYMBOL_SD_CARD', value: '' },
+  { label: 'LV_SYMBOL_NEW_LINE', value: '' }
 ]
 
 /**

+ 2 - 1
src/renderer/src/lvgl-widgets/button-matrix/ButtonMatrix.vue

@@ -110,7 +110,8 @@ const getProps = computed((): Record<string, CSSProperties> => {
       /* x 偏移量 | y 偏移量 | 阴影模糊半径 | 阴影扩散半径 | 阴影颜色 */
       boxShadow: itemsStyle?.shadow
         ? `${itemsStyle.shadow?.x}px ${itemsStyle.shadow?.y}px ${itemsStyle.shadow?.width}px ${itemsStyle.shadow?.spread}px ${itemsStyle.shadow?.color}`
-        : 'none'
+        : 'none',
+      overflow: 'hidden'
     },
     columnStyle: {
       gap: `${mainStyle?.gap.column}px`

+ 4 - 1
src/renderer/src/lvgl-widgets/button-matrix/index.tsx

@@ -174,10 +174,13 @@ export default {
           options: flagOptions,
           defaultCollapsed: true
         }
-      },
+      }
+    ],
+    coreProps: [
       {
         label: '属性',
         field: 'props.group',
+        valueType: '',
         render: (val) => {
           return <Config values={val} />
         }

+ 7 - 3
src/renderer/src/lvgl-widgets/button/index.ts

@@ -137,13 +137,17 @@ export default {
           options: flagOptions,
           defaultCollapsed: true
         }
-      },
+      }
+    ],
+    // 核心属性
+    coreProps: [
       {
         label: '文本',
         field: 'props.text',
-        valueType: 'text',
+        valueType: 'textarea',
         componentProps: {
-          useSymbol: true
+          useSymbol: true,
+          rows: 3
         }
       },
       {

+ 4 - 5
src/renderer/src/lvgl-widgets/checkbox/index.ts

@@ -143,14 +143,13 @@ export default {
           options: flagOptions,
           defaultCollapsed: true
         }
-      },
+      }
+    ],
+    coreProps: [
       {
         label: '文本',
         field: 'props.text',
-        valueType: 'text',
-        componentProps: {
-          useSymbol: true
-        }
+        valueType: 'text'
       }
     ],
     // 组件样式

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

@@ -120,6 +120,19 @@ export default {
           }
         ]
       },
+      {
+        label: '滚动条',
+        field: 'props.scrollbar',
+        valueType: 'select',
+        componentProps: {
+          options: [
+            { label: 'On', value: 'on' },
+            { label: 'Off', value: 'off' },
+            { label: 'Auto', value: 'auto' },
+            { label: 'Active', value: 'active' }
+          ]
+        }
+      },
       {
         label: '添加标识',
         field: 'props.addFlags',
@@ -137,19 +150,6 @@ export default {
           options: flagOptions,
           defaultCollapsed: true
         }
-      },
-      {
-        label: '滚动条',
-        field: 'props.scrollbar',
-        valueType: 'select',
-        componentProps: {
-          options: [
-            { label: 'On', value: 'on' },
-            { label: 'Off', value: 'off' },
-            { label: 'Auto', value: 'auto' },
-            { label: 'Active', value: 'active' }
-          ]
-        }
       }
     ],
     // 组件样式

+ 1 - 0
src/renderer/src/lvgl-widgets/dropdown/Dropdown.vue

@@ -65,6 +65,7 @@ const getProps = computed((): Record<string, CSSProperties> => {
     mainStyle: {
       width: `${props.width}px`,
       height: `${props.height}px`,
+      overflow: 'hidden',
 
       fontSize: `${mainStyle?.text.size}px`,
       color: mainStyle?.text?.color,

+ 3 - 1
src/renderer/src/lvgl-widgets/dropdown/index.tsx

@@ -180,7 +180,9 @@ export default {
           options: flagOptions,
           defaultCollapsed: true
         }
-      },
+      }
+    ],
+    coreProps: [
       {
         label: '绘制箭头图标',
         field: 'props.showArrow',

+ 1 - 0
src/renderer/src/lvgl-widgets/image-button/ImageButton.vue

@@ -54,6 +54,7 @@ const getProps = computed(() => {
     style: {
       width: `${props.width}px`,
       height: `${props.height}px`,
+      overflow: 'hidden',
 
       fontSize: `${stateStyles?.text.size}px`,
       color: stateStyles?.text?.color,

+ 11 - 15
src/renderer/src/lvgl-widgets/image-button/index.ts

@@ -61,18 +61,12 @@ export default {
     // 组件属性
     props: [
       {
-        label: '基本属性',
-        valueType: 'group',
-        children: [
-          {
-            label: '名称',
-            field: 'name',
-            valueType: 'text',
-            componentProps: {
-              placeholder: '请输入名称'
-            }
-          }
-        ]
+        label: '名称',
+        field: 'name',
+        valueType: 'text',
+        componentProps: {
+          placeholder: '请输入名称'
+        }
       },
       {
         label: '位置/大小',
@@ -119,7 +113,7 @@ export default {
       {
         label: '添加标识',
         field: 'props.addFlags',
-        valueType: 'select',
+        valueType: 'checkbox',
         componentProps: {
           options: flagOptions,
           defaultCollapsed: true
@@ -128,12 +122,14 @@ export default {
       {
         label: '删除标识',
         field: 'props.removeFlags',
-        valueType: 'select',
+        valueType: 'checkbox',
         componentProps: {
           options: flagOptions,
           defaultCollapsed: true
         }
-      },
+      }
+    ],
+    coreProps: [
       {
         label: '文本',
         field: 'props.text',

+ 3 - 1
src/renderer/src/lvgl-widgets/image/index.ts

@@ -106,7 +106,9 @@ export default {
           options: flagOptions,
           defaultCollapsed: true
         }
-      },
+      }
+    ],
+    coreProps: [
       {
         label: '图片',
         field: 'props.image',

+ 7 - 6
src/renderer/src/lvgl-widgets/label/Label.vue

@@ -3,7 +3,7 @@
 </template>
 
 <script setup lang="ts">
-import { computed } from 'vue'
+import { computed, CSSProperties } from 'vue'
 const props = defineProps<{
   width: number
   height: number
@@ -12,23 +12,24 @@ const props = defineProps<{
   state?: string
 }>()
 
-const getProps = computed(() => {
+const getProps = computed((): Record<string, CSSProperties> => {
   const styles = props.styles
   const stateStyles = styles.find((item) => item.state === props.state)
 
   return {
-    class: 'button',
     style: {
       width: `${props.width}px`,
       height: `${props.height}px`,
+      overflow: 'hidden',
 
       backgroundColor: stateStyles?.background.color,
 
       fontSize: `${stateStyles?.text.size}px`,
       color: stateStyles?.text?.color,
-      display: 'flex',
-      justifyContent: stateStyles?.text?.align || 'center',
-      alignItems: 'center',
+      textAlign: 'center',
+      wordBreak: 'break-all',
+
+      letterSpacing: `${stateStyles?.gap.column}px`,
 
       borderRadius: `${stateStyles?.border.radius}px`,
       borderStyle: 'solid',

+ 3 - 1
src/renderer/src/lvgl-widgets/label/index.ts

@@ -147,7 +147,9 @@ export default {
           options: flagOptions,
           defaultCollapsed: true
         }
-      },
+      }
+    ],
+    coreProps: [
       {
         label: '文本',
         field: 'props.text',

+ 2 - 2
src/renderer/src/lvgl-widgets/label/style.json

@@ -19,7 +19,7 @@
               "color": "#000000ff",
               "family": "xx",
               "size": 16,
-              "weight": 500,
+              "weight": "normal",
               "align": "center"
             },
             "gap": {
@@ -61,7 +61,7 @@
               "color": "#000000ff",
               "family": "xx",
               "size": 16,
-              "weight": 500,
+              "weight": "normal",
               "align": "center"
             },
             "gap": {

+ 7 - 2
src/renderer/src/lvgl-widgets/span-group/index.tsx

@@ -145,7 +145,9 @@ export default {
           options: flagOptions,
           defaultCollapsed: true
         }
-      },
+      }
+    ],
+    coreProps: [
       {
         label: '模式',
         field: 'props.mode',
@@ -176,7 +178,10 @@ export default {
       {
         label: '背景',
         field: 'background',
-        valueType: 'background'
+        valueType: 'background',
+        componentProps: {
+          onlyColor: true
+        }
       },
       {
         label: '边框',

+ 3 - 1
src/renderer/src/lvgl-widgets/textarea/index.ts

@@ -163,7 +163,9 @@ export default {
           options: flagOptions,
           defaultCollapsed: true
         }
-      },
+      }
+    ],
+    coreProps: [
       {
         label: '文本',
         field: 'props.text',

+ 6 - 2
src/renderer/src/lvgl-widgets/type.d.ts

@@ -102,9 +102,13 @@ export interface IComponentModelConfig {
    */
   config: {
     /**
-     * 组件属性配置
+     * 基础属性配置
      */
     props?: ComponentSchema[]
+    /**
+     * 核心属性
+     */
+    coreProps?: ComponentSchema[]
     /**
      * 样式属性配置
      */
@@ -198,7 +202,7 @@ export interface IStyleConfig {
     x: number
     // 起始坐标y
     y: number
-    // 蔓延
+    // 扩散
     spread: number
     // 模糊宽度
     width: number

+ 5 - 0
src/renderer/src/style.less

@@ -11,6 +11,11 @@ body {
     border-color 0.3s ease;
 }
 
+@font-face {
+  font-family: LVGL_Icons;
+  src: url(./assets/FontAwesome5-Solid+Brands+Regular.woff) format('woff');
+}
+
 
 .el-tabs {
   --el-tabs-header-height: 32px !important;

+ 6 - 1
src/renderer/src/views/designer/config/property/CusFormItem.vue

@@ -1,6 +1,11 @@
 <template>
   <el-col v-if="!schema?.hide" :span="schema?.componentProps?.span ?? 24">
-    <el-form-item v-if="isFormItem" :prop="schema.field" :label="schema.label">
+    <el-form-item
+      v-if="isFormItem"
+      :prop="schema.field"
+      :label="schema.label"
+      :label-width="schema.label ? '90px' : '0px'"
+    >
       <!-- 文本 -->
       <el-input v-if="schema.valueType === 'text'" v-model="value" v-bind="schema?.componentProps">
         <template #prefix>

+ 36 - 4
src/renderer/src/views/designer/config/property/components/CusTextarea.vue

@@ -1,9 +1,41 @@
 <template>
-  <div>
-    <el-input type="textarea" v-model="value" placeholder="请输入内容" />
+  <div class="w-full relative">
+    <el-input
+      type="textarea"
+      v-model="modelValue"
+      placeholder="请输入内容"
+      :rows="rows"
+      v-bind="$attrs"
+    />
+    <LuSmilePlus
+      v-if="useSymbol"
+      size="12px"
+      class="cursor-pointer absolute top--20px right-0px"
+      @click="handleOpenSymbolModal"
+    />
   </div>
+  <SymbolSelectModal v-if="useSymbol" ref="symbolModalRef" @select="handleSelectSymbol" />
 </template>
 
-<script setup>
-const value = defineModel < string > ('modelValue', { type: String })
+<script setup lang="ts">
+import { ref } from 'vue'
+import { LuSmilePlus } from 'vue-icons-plus/lu'
+import SymbolSelectModal from './SymbolSelectModal.vue'
+
+defineProps<{
+  useSymbol?: boolean
+  rows?: number
+}>()
+const modelValue = defineModel<string>('modelValue')
+const symbolModalRef = ref<InstanceType<typeof SymbolSelectModal>>()
+
+const handleOpenSymbolModal = () => {
+  symbolModalRef.value?.open()
+}
+
+const handleSelectSymbol = (val: string) => {
+  if (val) {
+    modelValue.value += `{${val}}`
+  }
+}
 </script>

+ 1 - 1
src/renderer/src/views/designer/config/property/components/ImageSelect.vue

@@ -1,6 +1,6 @@
 <template>
   <el-dialog title="图片选择" v-model="visible" width="800px">
-    <div class="flex h-300px overflow-y-auto gap-8px flex-wrap">
+    <div class="flex h-320px overflow-y-auto gap-8px flex-wrap">
       <div
         class="w-100px h-100px border-solid border-border cursor-pointer flex flex-col"
         v-for="item in imageList"

+ 22 - 17
src/renderer/src/views/designer/config/property/components/StyleBorder.vue

@@ -4,23 +4,28 @@
       <ColorPicker v-model:pureColor="color" format="hex8" picker-type="chrome" use-type="pure" />
       <span class="text-text-active">{{ modelValue?.color }}</span>
     </el-form-item>
-    <el-form-item label="宽度" label-position="left" label-width="60px">
-      <el-input-number
-        placeholder="边框宽度"
-        v-model="width"
-        controls-position="right"
-        style="width: 100%"
-      />
-    </el-form-item>
-    <el-form-item label="圆角" label-position="left" label-width="60px">
-      <el-input-number
-        placeholder="边框圆角"
-        v-model="radius"
-        controls-position="right"
-        style="width: 100%"
-      />
-    </el-form-item>
-    <el-form-item label="边框" label-position="left" label-width="60px">
+    <el-row :gutter="12">
+      <el-col :span="12">
+        <el-form-item label-position="left" label-width="0px">
+          <el-input-number v-model="width" controls-position="right" style="width: 100%" :min="0">
+            <template #prefix>
+              <span>宽度</span>
+            </template>
+          </el-input-number>
+        </el-form-item>
+      </el-col>
+      <el-col :span="12">
+        <el-form-item label-position="left" label-width="0px">
+          <el-input-number v-model="radius" controls-position="right" style="width: 100%" :min="0">
+            <template #prefix>
+              <span>圆角</span>
+            </template>
+          </el-input-number>
+        </el-form-item>
+      </el-col>
+    </el-row>
+
+    <el-form-item label-position="left" label-width="0px">
       <div class="flex-1 flex items-center justify-between px-4px">
         <BsBorderOuter
           class="cursor-pointer"

+ 2 - 0
src/renderer/src/views/designer/config/property/components/StyleFont.vue

@@ -17,6 +17,8 @@
         controls-position="right"
         placeholder="请输入"
         style="width: 100%"
+        :min="1"
+        :max="1000"
       />
     </el-form-item>
     <el-form-item label="字重" label-position="left" label-width="60px">

+ 5 - 1
src/renderer/src/views/designer/config/property/components/StyleGap.vue

@@ -6,14 +6,18 @@
         v-model="row"
         controls-position="right"
         style="width: 100%"
+        :min="0"
+        :max="100"
       />
     </el-form-item>
-    <el-form-item label="间距" label-position="left" label-width="60px">
+    <el-form-item label="间距" label-position="left" label-width="60px">
       <el-input-number
         placeholder="请输入"
         v-model="column"
         controls-position="right"
         style="width: 100%"
+        :min="0"
+        :max="100"
       />
     </el-form-item>
   </div>

+ 62 - 32
src/renderer/src/views/designer/config/property/components/StyleMargin.vue

@@ -1,37 +1,67 @@
 <template>
   <div>
-    <el-form-item label="Top" label-position="left" label-width="60px">
-      <el-input-number
-        placeholder="请输入"
-        v-model="top"
-        controls-position="right"
-        style="width: 100%"
-      />
-    </el-form-item>
-    <el-form-item label="Right" label-position="left" label-width="60px">
-      <el-input-number
-        placeholder="请输入"
-        v-model="right"
-        controls-position="right"
-        style="width: 100%"
-      />
-    </el-form-item>
-    <el-form-item label="Bottom" label-position="left" label-width="60px">
-      <el-input-number
-        placeholder="请输入"
-        v-model="bottom"
-        controls-position="right"
-        style="width: 100%"
-      />
-    </el-form-item>
-    <el-form-item label="Left" label-position="left" label-width="60px">
-      <el-input-number
-        placeholder="请输入"
-        v-model="left"
-        controls-position="right"
-        style="width: 100%"
-      />
-    </el-form-item>
+    <el-row :gutter="12">
+      <el-col :span="12">
+        <el-form-item label="" label-position="left" label-width="0px">
+          <el-input-number
+            v-model="top"
+            controls-position="right"
+            style="width: 100%"
+            :min="0"
+            :max="200"
+          >
+            <template #prefix>
+              <span>上</span>
+            </template>
+          </el-input-number>
+        </el-form-item>
+      </el-col>
+      <el-col :span="12">
+        <el-form-item label="" label-position="left" label-width="0px">
+          <el-input-number
+            v-model="right"
+            controls-position="right"
+            style="width: 100%"
+            :min="0"
+            :max="200"
+          >
+            <template #prefix>
+              <span>右</span>
+            </template>
+          </el-input-number>
+        </el-form-item>
+      </el-col>
+      <el-col :span="12">
+        <el-form-item label="" label-position="left" label-width="0px">
+          <el-input-number
+            v-model="bottom"
+            controls-position="right"
+            style="width: 100%"
+            :min="0"
+            :max="200"
+          >
+            <template #prefix>
+              <span>下</span>
+            </template>
+          </el-input-number>
+        </el-form-item>
+      </el-col>
+      <el-col :span="12">
+        <el-form-item label="" label-position="left" label-width="0px">
+          <el-input-number
+            v-model="left"
+            controls-position="right"
+            style="width: 100%"
+            :min="0"
+            :max="200"
+          >
+            <template #prefix>
+              <span>左</span>
+            </template>
+          </el-input-number>
+        </el-form-item>
+      </el-col>
+    </el-row>
   </div>
 </template>
 

+ 64 - 33
src/renderer/src/views/designer/config/property/components/StylePadding.vue

@@ -1,44 +1,75 @@
 <template>
   <div v-if="!allInOne">
-    <el-form-item label="Top" label-position="left" label-width="60px">
-      <el-input-number
-        placeholder="请输入"
-        v-model="top"
-        controls-position="right"
-        style="width: 100%"
-      />
-    </el-form-item>
-    <el-form-item label="Right" label-position="left" label-width="60px">
-      <el-input-number
-        placeholder="请输入"
-        v-model="right"
-        controls-position="right"
-        style="width: 100%"
-      />
-    </el-form-item>
-    <el-form-item label="Bottom" label-position="left" label-width="60px">
-      <el-input-number
-        placeholder="请输入"
-        v-model="bottom"
-        controls-position="right"
-        style="width: 100%"
-      />
-    </el-form-item>
-    <el-form-item label="Left" label-position="left" label-width="60px">
-      <el-input-number
-        placeholder="请输入"
-        v-model="left"
-        controls-position="right"
-        style="width: 100%"
-      />
-    </el-form-item>
+    <el-row :gutter="12">
+      <el-col :span="12">
+        <el-form-item label="" label-position="left" label-width="0px">
+          <el-input-number
+            v-model="top"
+            controls-position="right"
+            style="width: 100%"
+            :min="0"
+            :max="200"
+          >
+            <template #prefix>
+              <span>上</span>
+            </template>
+          </el-input-number>
+        </el-form-item>
+      </el-col>
+      <el-col :span="12">
+        <el-form-item label="" label-position="left" label-width="0px">
+          <el-input-number
+            v-model="right"
+            controls-position="right"
+            style="width: 100%"
+            :min="0"
+            :max="200"
+          >
+            <template #prefix>
+              <span>右</span>
+            </template>
+          </el-input-number>
+        </el-form-item>
+      </el-col>
+      <el-col :span="12">
+        <el-form-item label="" label-position="left" label-width="0px">
+          <el-input-number
+            v-model="bottom"
+            controls-position="right"
+            style="width: 100%"
+            :min="0"
+            :max="200"
+          >
+            <template #prefix>
+              <span>下</span>
+            </template>
+          </el-input-number>
+        </el-form-item>
+      </el-col>
+      <el-col :span="12">
+        <el-form-item label="" label-position="left" label-width="0px">
+          <el-input-number
+            v-model="left"
+            controls-position="right"
+            style="width: 100%"
+            :min="0"
+            :max="200"
+          >
+            <template #prefix>
+              <span>左</span>
+            </template>
+          </el-input-number>
+        </el-form-item>
+      </el-col>
+    </el-row>
   </div>
   <div v-else>
     <el-input-number
-      placeholder="请输入"
       v-model="all"
       controls-position="right"
       style="width: 100%"
+      :min="0"
+      :max="200"
     >
       <template #prefix>
         <span>P</span>

+ 68 - 34
src/renderer/src/views/designer/config/property/components/StyleShadow.vue

@@ -4,38 +4,72 @@
       <ColorPicker v-model:pureColor="color" format="hex8" picker-type="chrome" use-type="pure" />
       <span class="text-text-active">{{ modelValue?.color }}</span>
     </el-form-item>
-    <el-form-item label="X" label-position="left" label-width="60px">
-      <el-input-number
-        placeholder="请输入"
-        v-model="x"
-        controls-position="right"
-        style="width: 100%"
-      />
-    </el-form-item>
-    <el-form-item label="Y" label-position="left" label-width="60px">
-      <el-input-number
-        placeholder="请输入"
-        v-model="y"
-        controls-position="right"
-        style="width: 100%"
-      />
-    </el-form-item>
-    <el-form-item label="宽度" label-position="left" label-width="60px">
-      <el-input-number
-        placeholder="请输入"
-        v-model="width"
-        controls-position="right"
-        style="width: 100%"
-      />
-    </el-form-item>
-    <el-form-item label="蔓延" label-position="left" label-width="60px">
-      <el-input-number
-        placeholder="请输入"
-        v-model="spread"
-        controls-position="right"
-        style="width: 100%"
-      />
-    </el-form-item>
+    <el-row :gutter="12">
+      <el-col :span="12">
+        <el-form-item label-position="left" label-width="0px">
+          <el-input-number
+            placeholder="请输入"
+            v-model="x"
+            controls-position="right"
+            style="width: 100%"
+            :min="0"
+            :max="100"
+          >
+            <template #prefix>
+              <span>X</span>
+            </template>
+          </el-input-number>
+        </el-form-item>
+      </el-col>
+      <el-col :span="12">
+        <el-form-item label-position="left" label-width="0px">
+          <el-input-number
+            placeholder="请输入"
+            v-model="y"
+            controls-position="right"
+            style="width: 100%"
+            :min="0"
+            :max="100"
+          >
+            <template #prefix>
+              <span>Y</span>
+            </template>
+          </el-input-number>
+        </el-form-item>
+      </el-col>
+      <el-col :span="12">
+        <el-form-item label-position="left" label-width="0px">
+          <el-input-number
+            placeholder="请输入"
+            v-model="width"
+            controls-position="right"
+            style="width: 100%"
+            :min="0"
+            :max="100"
+          >
+            <template #prefix>
+              <span>宽度</span>
+            </template>
+          </el-input-number>
+        </el-form-item>
+      </el-col>
+      <el-col :span="12">
+        <el-form-item label-position="left" label-width="0px">
+          <el-input-number
+            placeholder="请输入"
+            v-model="spread"
+            controls-position="right"
+            style="width: 100%"
+            :min="0"
+            :max="100"
+          >
+            <template #prefix>
+              <span>扩散</span>
+            </template>
+          </el-input-number>
+        </el-form-item>
+      </el-col>
+    </el-row>
   </div>
 </template>
 
@@ -49,7 +83,7 @@ const modelValue = defineModel<{
   x: number
   // 起始坐标y
   y: number
-  // 蔓延
+  // 扩散
   spread: number
   // 模糊宽度
   width: number
@@ -85,7 +119,7 @@ const y = computed({
   }
 })
 
-// 蔓延
+// 扩散
 const spread = computed({
   get: () => modelValue.value?.spread,
   set: (val: number) => {

+ 40 - 0
src/renderer/src/views/designer/config/property/components/SymbolSelectModal.vue

@@ -0,0 +1,40 @@
+<template>
+  <el-dialog title="选择图标" v-model="visible" width="500px">
+    <div class="h-200px flex flex-wrap items-center gap-4px">
+      <i
+        class="text-20px symbol-font w-30px h-30px cursor-pointer hover:bg-bg-tertiary not-italic grid place-items-center rounded-4px"
+        v-for="item in symbols"
+        :key="item.value"
+        :title="item.label"
+        v-html="item.value"
+        @click="handleClick(item.label)"
+      ></i>
+    </div>
+  </el-dialog>
+</template>
+
+<script setup lang="ts">
+import { ref } from 'vue'
+import { symbols } from '@/constants'
+
+const visible = ref(false)
+
+defineExpose({
+  open() {
+    visible.value = true
+  }
+})
+
+const emit = defineEmits(['select'])
+
+const handleClick = (label: string) => {
+  emit('select', label)
+  visible.value = false
+}
+</script>
+
+<style lang="less" scoped>
+.symbol-font {
+  font-family: LVGL_Icons;
+}
+</style>

+ 46 - 9
src/renderer/src/views/designer/config/property/index.vue

@@ -1,16 +1,38 @@
 <template>
   <el-scrollbar ref="scrollbarRef" height="calc(100vh - 198px)">
+    <!-- 基础属性 -->
+    <el-form
+      ref="formRef"
+      class="px-12px border-box mt-12px"
+      label-position="top"
+      :model="projectStore.activeWidget"
+    >
+      <el-row :gutter="12">
+        <CusFormItem
+          v-for="(item, index) in formConfig.props || []"
+          :key="item.valueType + '_' + index"
+          :schema="item"
+          :formData="projectStore.activeWidget!"
+        />
+      </el-row>
+    </el-form>
     <el-collapse v-model="activeKeys">
-      <el-collapse-item title="属性配置" name="props">
+      <el-collapse-item name="props" v-if="formConfig?.coreProps">
+        <template #title>
+          <div class="flex items-center">
+            <LuSliders size="12px" />
+            <span class="ml-4px text-12px">核心属性</span>
+          </div>
+        </template>
         <el-form
           ref="formRef"
-          class="px-12px border-box"
+          class="px-12px border-box mt-12px"
           label-position="top"
           :model="projectStore.activeWidget"
         >
           <el-row :gutter="12">
             <CusFormItem
-              v-for="(item, index) in formConfig.props || []"
+              v-for="(item, index) in formConfig.coreProps || []"
               :key="item.valueType + '_' + index"
               :schema="item"
               :formData="projectStore.activeWidget!"
@@ -18,20 +40,33 @@
           </el-row>
         </el-form>
       </el-collapse-item>
-      <el-collapse-item title="样式配置" name="style">
+      <el-collapse-item name="style">
+        <template #title>
+          <div class="flex items-center">
+            <IoColorPaletteOutline size="12px" />
+            <span class="ml-4px text-12px">样式配置</span>
+          </div>
+        </template>
         <el-form
           ref="formRef"
           class="px-12px border-box"
           label-position="top"
           :model="projectStore.activeWidget"
         >
-          <el-card
+          <el-form-item
             v-if="formConfig.styles?.find((item) => item.field === 'part')"
-            header="模块/状态"
-            class="mb-12px"
+            label="模块/状态"
+            class="mb-12px!"
           >
-            <StylePart v-model="part" :hasStyle="!!styleFormData" @change="onChangeStyleByState" />
-          </el-card>
+            <div class="w-full">
+              <StylePart
+                v-model="part"
+                :hasStyle="!!styleFormData"
+                @change="onChangeStyleByState"
+              />
+            </div>
+          </el-form-item>
+
           <el-row :gutter="12" v-if="styleFormData">
             <CusFormItem
               v-for="(item, index) in formConfig.styles || []"
@@ -54,6 +89,8 @@ 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'
 
 const projectStore = useProjectStore()
 const activeKeys = ref<string[]>(['props', 'style'])

+ 0 - 1
src/renderer/src/views/designer/workspace/stage/Moveable.vue

@@ -142,7 +142,6 @@ useMutationObserver(
 const zIndex = ref()
 
 const individualGroupableProps = (element: HTMLElement | SVGElement | null | undefined) => {
-  console.log(element?.getAttribute('widget-type'))
   if (element?.getAttribute('widget-type') === 'lv_checkbox') {
     return { resizable: false }
   }

+ 1 - 0
src/renderer/src/views/designer/workspace/stage/Node.vue

@@ -118,6 +118,7 @@ useDrop(nodeRef, {
   // 元素放置
   onDom: (content, event) => {
     dropStyle.value = {}
+    event?.stopPropagation()
     if (!content) return
     // 创建控件
     const { offsetX = 0, offsetY = 0 } = event || {}