Browse Source

fix: 修改变量控件等问题

liaojiaxing 1 week ago
parent
commit
d6c738e7ad

+ 1 - 2
src/renderer/src/lvgl-widgets/bar/index.ts

@@ -226,8 +226,7 @@ export default {
         valueType: 'dependency',
         name: ['props.mode'],
         dependency: (dependency) => {
-          return dependency['props.mode'] === 'range' ||
-            dependency['props.mode']?.originValue === 'range'
+          return dependency['props.mode'] === 'range'
             ? [
                 {
                   label: '',

+ 1 - 2
src/renderer/src/lvgl-widgets/slider/index.ts

@@ -230,8 +230,7 @@ export default {
         valueType: 'dependency',
         name: ['props.mode'],
         dependency: (dependency) => {
-          return dependency['props.mode'] === 'range' ||
-            dependency['props.mode']?.originValue === 'range'
+          return dependency['props.mode'] === 'range'
             ? [
                 {
                   label: '',

+ 68 - 22
src/renderer/src/utils/variableBinding.ts

@@ -6,7 +6,7 @@ import type { BaseWidget } from '@/types/baseWidget'
  * 判断属性值是否绑定了变量
  */
 export function isVariableBound(value: any): value is VariableBinding {
-  return typeof value === 'object' && 'varId' in value
+  return value !== null && typeof value === 'object' && 'varId' in value
 }
 
 /**
@@ -121,28 +121,50 @@ export function getAllVariables(
 export function findVariableUsages(
   varId: string,
   widgets: BaseWidget[]
-): Array<{ widgetId: string; widgetName: string; fieldPath: string }> {
-  const usages: Array<{ widgetId: string; widgetName: string; fieldPath: string }> = []
+): Array<{ widgetId: string; widget: BaseWidget; fieldPath: string }> {
+  const usages: Array<{ widgetId: string; widget: BaseWidget; fieldPath: string }> = []
+
+  function collectUsages(widget: BaseWidget, value: any, fieldPath: string) {
+    if (isVariableBound(value)) {
+      if (value.varId === varId) {
+        usages.push({
+          widgetId: widget.id,
+          widget,
+          fieldPath
+        })
+      }
+      return
+    }
 
-  function traverse(widget: BaseWidget, parentPath: string = '') {
-    const widgetPath = parentPath ? `${parentPath}.${widget.name}` : widget.name
+    if (!value || typeof value !== 'object') {
+      return
+    }
 
-    if (widget.props) {
-      for (const [key, value] of Object.entries(widget.props)) {
-        const fieldPath = `${widgetPath}.props.${key}`
-
-        if (isVariableBound(value) && value.varId === varId) {
-          usages.push({
-            widgetId: widget.id,
-            widgetName: widget.name,
-            fieldPath
-          })
-        }
+    if (Array.isArray(value)) {
+      for (let index = 0; index < value.length; index++) {
+        collectUsages(widget, value[index], `${fieldPath}.${index}`)
       }
+      return
+    }
+
+    const keys = Object.keys(value)
+    for (let index = 0; index < keys.length; index++) {
+      const key = keys[index]
+      collectUsages(widget, value[key], `${fieldPath}.${key}`)
+    }
+  }
+
+  function traverse(widget: BaseWidget) {
+    if (widget.props) {
+      collectUsages(widget, widget.props, 'props')
+    }
+
+    if (widget.style) {
+      collectUsages(widget, widget.style, 'style')
     }
 
     if (widget.children) {
-      widget.children.forEach((child) => traverse(child, widgetPath))
+      widget.children.forEach((child) => traverse(child))
     }
   }
 
@@ -154,13 +176,37 @@ export function findVariableUsages(
  * 自动解绑指定变量的所有引用
  */
 export function unbindAllVariableReferences(varId: string, widgets: BaseWidget[]): void {
+  function restoreValue(value: any): any {
+    if (isVariableBound(value)) {
+      return value.varId === varId ? value.originValue : value
+    }
+
+    if (!value || typeof value !== 'object') {
+      return value
+    }
+
+    if (Array.isArray(value)) {
+      for (let index = 0; index < value.length; index++) {
+        value[index] = restoreValue(value[index])
+      }
+      return value
+    }
+
+    const keys = Object.keys(value)
+    for (let index = 0; index < keys.length; index++) {
+      const key = keys[index]
+      value[key] = restoreValue(value[key])
+    }
+    return value
+  }
+
   function traverse(widget: BaseWidget) {
     if (widget.props) {
-      for (const [key, value] of Object.entries(widget.props)) {
-        if (isVariableBound(value) && value.varId === varId) {
-          widget.props[key] = value.originValue
-        }
-      }
+      widget.props = restoreValue(widget.props)
+    }
+
+    if (widget.style) {
+      widget.style = restoreValue(widget.style)
     }
 
     if (widget.children) {

+ 37 - 14
src/renderer/src/views/designer/config/VariableConfig.vue

@@ -14,9 +14,11 @@
               <template #default="{ row }">
                 <el-input
                   spellcheck="false"
-                  v-model="row.name"
+                  :model-value="row.name"
                   placeholder="请输入"
-                  @input="(val) => handleVariableNameInput(row, val)"
+                  @update:model-value="
+                    (val) => handleVariableNameInput(row, val, pageVariables || [])
+                  "
                 />
               </template>
             </el-table-column>
@@ -94,9 +96,11 @@
                     <template #default="{ row }">
                       <el-input
                         spellcheck="false"
-                        v-model="row.name"
+                        :model-value="row.name"
                         placeholder="请输入"
-                        @input="(val) => handleVariableNameInput(row, val)"
+                        @update:model-value="
+                          (val) => handleVariableNameInput(row, val, item.variables)
+                        "
                       />
                     </template>
                   </el-table-column>
@@ -145,12 +149,12 @@
 <script setup lang="ts">
 import { computed, ref } from 'vue'
 import { ArrowRight, Plus, Delete } from '@element-plus/icons-vue'
-import { ElMessageBox } from 'element-plus'
+import { ElMessage, ElMessageBox } from 'element-plus'
 import { variableType } from '@/constants'
 import { v4 } from 'uuid'
 import { useI18n } from 'vue-i18n'
 import { useProjectStore } from '@/store/modules/project'
-import { findVariableUsages } from '@/utils/variableBinding'
+import { findVariableUsages, unbindAllVariableReferences } from '@/utils/variableBinding'
 import { SplitterCollapse, SplitterCollapseItem } from '@/components/SplitterCollapse'
 
 import type { Variable, VariableGroup } from '@/types/variables'
@@ -185,14 +189,34 @@ const normalizeCVariableName = (value: string) => {
   return validChars.replace(/^[0-9]+/, '')
 }
 
-const handleVariableNameInput = (row: Variable, value: string) => {
-  row.name = normalizeCVariableName(value)
+const isDuplicateVariableName = (variables: Variable[], row: Variable, name: string) => {
+  return !!name && variables.some((item) => item.id !== row.id && item.name === name)
+}
+
+const handleVariableNameInput = (row: Variable, value: string, variables: Variable[]) => {
+  const name = normalizeCVariableName(value)
+
+  if (isDuplicateVariableName(variables, row, name)) {
+    ElMessage.warning('同一组下变量名不能重复')
+    return
+  }
+
+  row.name = name
 }
 
 const addVariables = (variables) => {
+  const names = new Set(variables.map((item) => item.name))
+  let index = variables.length + 1
+  let name = `var_${index}`
+
+  while (names.has(name)) {
+    index += 1
+    name = `var_${index}`
+  }
+
   variables.unshift({
     id: v4(),
-    name: `var_${variables.length + 1}`,
+    name,
     value: '',
     type: 'char'
   })
@@ -251,17 +275,15 @@ const handleVariablesRemove = (
   }
 
   const pages = projectStore.project?.screens.flatMap((item) => item.pages) || []
-  const usageCount = findVariableUsages(varItem.id, [
-    { children: pages }
-  ] as unknown as BaseWidget[]).length
+  const usages = findVariableUsages(varItem.id, [{ children: pages }] as unknown as BaseWidget[])
 
-  if (usageCount === 0) {
+  if (usages.length === 0) {
     deleteVariable()
     return
   }
 
   ElMessageBox.confirm(
-    `当前变量已被 ${usageCount} 处${scope === 'global' ? '控件属性' : '页面控件属性'}使用,删除后相关绑定将失效,是否继续删除?`,
+    `当前变量已被 ${usages.length} 处${scope === 'global' ? '控件属性' : '页面控件属性'}使用,删除后相关绑定将失效,是否继续删除?`,
     '提示',
     {
       confirmButtonText: '确定',
@@ -270,6 +292,7 @@ const handleVariablesRemove = (
     }
   ).then(() => {
     deleteVariable()
+    unbindAllVariableReferences(varItem.id, [{ children: pages }] as unknown as BaseWidget[])
   })
 }
 

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

@@ -333,6 +333,7 @@ import { LuLanguages } from 'vue-icons-plus/lu'
 import VariableBindWrapper from './components/VariableBindWrapper.vue'
 import { useAllWidgets } from '@/hooks/useAllWidgets'
 import { isDuplicateWidgetName } from '@/utils/widgetName'
+import { getAllVariables, getPropertyDisplayValue } from '@/utils/variableBinding'
 
 defineOptions({
   name: 'CusFormItem'
@@ -363,6 +364,9 @@ const componentProps = computed(() => {
   return rest
 })
 const expandStyle = ref(true)
+const allVariables = computed(() =>
+  getAllVariables(projectStore.project?.variables || [], projectStore.activePage?.variables)
+)
 
 const formItemRules = computed<FormItemRule[]>(() => {
   const rules = [...(props.schema.rules || [])]
@@ -555,7 +559,7 @@ const dependencyFormItems = computed(() => {
     const values: { [key: string]: any } = {}
     schema?.name?.forEach((key) => {
       const val = get(formData, key) ?? get(widgetData, key)
-      values[key] = val
+      values[key] = getPropertyDisplayValue(val, allVariables.value)
     })
     const result = schema.dependency(values) || []
     return Array.isArray(result) ? result : [result]

+ 9 - 0
src/renderer/src/views/designer/config/property/components/VariableBindWrapper.vue

@@ -133,11 +133,20 @@ const addPageVariables = () => {
   // 4、用户确认后创建变量到页面变量,并自动绑定
   popoverRef.value?.hide()
 
+  const variableNames = new Set(
+    getAllVariables(projectStore.project?.variables || [], projectStore.activePage?.variables)
+      .flatMap((group) => group.variables)
+      .map((variable) => variable.name)
+  )
+
   ElMessageBox.prompt('请输入变量名称', '提示', {
     confirmButtonText: '确认',
     cancelButtonText: '取消',
     // C语言变量命名规则:只能包含字母、数字和下划线,且必须以字母或下划线开头
     inputPattern: /^[a-zA-Z_][a-zA-Z0-9_]*$/,
+    inputValidator: (value) => {
+      return variableNames.has(value) ? '变量名不能重复' : true
+    },
     inputErrorMessage: '变量名称只能包含字母、数字和下划线,且必须以字母或下划线开头'
   })
     .then(({ value }) => {