Эх сурвалжийг харах

perf:【IoT 物联网】场景联动触发器优化

puhui999 10 сар өмнө
parent
commit
929bcb4059

+ 2 - 0
src/api/iot/rule/scene/scene.types.ts

@@ -151,6 +151,8 @@ interface ActionFormData {
 
 
 interface ConditionGroupFormData {
 interface ConditionGroupFormData {
   conditions: ConditionFormData[]
   conditions: ConditionFormData[]
+  // 注意:条件组内部的条件固定为"且"关系,条件组之间固定为"或"关系
+  // logicOperator 字段保留用于兼容性,但在UI中固定为 'AND'
   logicOperator: 'AND' | 'OR'
   logicOperator: 'AND' | 'OR'
 }
 }
 
 

+ 0 - 1
src/views/iot/rule/scene/form/RuleSceneForm.vue

@@ -44,7 +44,6 @@ import ActionSection from './sections/ActionSection.vue'
 import {
 import {
   RuleSceneFormData,
   RuleSceneFormData,
   IotRuleScene,
   IotRuleScene,
-  IotRuleSceneTriggerTypeEnum,
   IotRuleSceneActionTypeEnum,
   IotRuleSceneActionTypeEnum,
   CommonStatusEnum
   CommonStatusEnum
 } from '@/api/iot/rule/scene/scene.types'
 } from '@/api/iot/rule/scene/scene.types'

+ 48 - 27
src/views/iot/rule/scene/form/configs/ConditionGroupConfig.vue

@@ -1,17 +1,37 @@
 <!-- 条件组配置组件 -->
 <!-- 条件组配置组件 -->
 <template>
 <template>
   <div class="p-16px">
   <div class="p-16px">
+    <!-- 条件组说明 -->
+    <div
+      v-if="group.conditions && group.conditions.length > 1"
+      class="mb-12px flex items-center justify-center"
+    >
+      <div
+        class="flex items-center gap-6px px-10px py-4px bg-green-50 border border-green-200 rounded-full text-11px text-green-600"
+      >
+        <Icon icon="ep:info-filled" />
+        <span>组内所有条件必须同时满足(且关系)</span>
+      </div>
+    </div>
+
     <div class="space-y-12px">
     <div class="space-y-12px">
       <!-- 条件列表 -->
       <!-- 条件列表 -->
       <div v-if="group.conditions && group.conditions.length > 0" class="space-y-12px">
       <div v-if="group.conditions && group.conditions.length > 0" class="space-y-12px">
         <div
         <div
           v-for="(condition, index) in group.conditions"
           v-for="(condition, index) in group.conditions"
           :key="`condition-${index}`"
           :key="`condition-${index}`"
-          class="p-12px border border-[var(--el-border-color-lighter)] rounded-6px bg-[var(--el-fill-color-light)]"
+          class="p-12px border border-[var(--el-border-color-lighter)] rounded-6px bg-[var(--el-fill-color-light)] shadow-sm hover:shadow-md transition-shadow"
         >
         >
           <div class="flex items-center justify-between mb-12px">
           <div class="flex items-center justify-between mb-12px">
             <div class="flex items-center gap-8px">
             <div class="flex items-center gap-8px">
-              <span class="text-14px font-500 text-[var(--el-text-color-primary)]">条件 {{ index + 1 }}</span>
+              <div class="flex items-center gap-6px">
+                <div
+                  class="w-18px h-18px bg-green-500 text-white rounded-full flex items-center justify-center text-10px font-bold"
+                >
+                  {{ index + 1 }}
+                </div>
+                <span class="text-14px font-500 text-[var(--el-text-color-primary)]">条件</span>
+              </div>
               <el-tag size="small" type="primary">
               <el-tag size="small" type="primary">
                 {{ getConditionTypeName(condition.type) }}
                 {{ getConditionTypeName(condition.type) }}
               </el-tag>
               </el-tag>
@@ -39,13 +59,21 @@
             />
             />
           </div>
           </div>
 
 
-          <!-- 逻辑连接符 -->
-          <!-- TODO @puhui999:不用这个哈; -->
-          <div v-if="index < group.conditions!.length - 1" class="flex justify-center mt-8px">
-            <el-select v-model="group.logicOperator" size="small" class="w-80px">
-              <el-option label="且" value="AND" />
-              <el-option label="或" value="OR" />
-            </el-select>
+          <!-- 条件间的"且"连接符 -->
+          <div
+            v-if="index < group.conditions!.length - 1"
+            class="flex items-center justify-center py-8px"
+          >
+            <div class="flex items-center gap-6px">
+              <!-- 连接线 -->
+              <div class="w-24px h-1px bg-green-300"></div>
+              <!-- 且标签 -->
+              <div class="px-12px py-4px bg-green-100 border-2 border-green-300 rounded-full">
+                <span class="text-12px font-600 text-green-600">且</span>
+              </div>
+              <!-- 连接线 -->
+              <div class="w-24px h-1px bg-green-300"></div>
+            </div>
           </div>
           </div>
         </div>
         </div>
       </div>
       </div>
@@ -53,10 +81,14 @@
       <!-- 空状态 -->
       <!-- 空状态 -->
       <div v-else class="py-40px text-center">
       <div v-else class="py-40px text-center">
         <el-empty description="暂无条件配置" :image-size="80">
         <el-empty description="暂无条件配置" :image-size="80">
-          <el-button type="primary" @click="addCondition">
-            <Icon icon="ep:plus" />
-            添加第一个条件
-          </el-button>
+          <template #description>
+            <div class="space-y-8px">
+              <p class="text-[var(--el-text-color-secondary)]">暂无条件配置</p>
+              <p class="text-12px text-[var(--el-text-color-placeholder)]">
+                条件组需要至少包含一个条件才能生效
+              </p>
+            </div>
+          </template>
         </el-empty>
         </el-empty>
       </div>
       </div>
 
 
@@ -71,20 +103,11 @@
           <Icon icon="ep:plus" />
           <Icon icon="ep:plus" />
           继续添加条件
           继续添加条件
         </el-button>
         </el-button>
-        <span class="block mt-8px text-12px text-[var(--el-text-color-secondary)]"> 最多可添加 {{ maxConditions }} 个条件 </span>
+        <span class="block mt-8px text-12px text-[var(--el-text-color-secondary)]">
+          最多可添加 {{ maxConditions }} 个条件
+        </span>
       </div>
       </div>
     </div>
     </div>
-
-    <!-- 验证结果 -->
-    <!-- TODO @puhui999:是不是不用这种提示;只要 validator rules 能展示出来就好了呀。。。 -->
-    <div v-if="validationMessage" class="mt-8px">
-      <el-alert
-        :title="validationMessage"
-        :type="isValid ? 'success' : 'error'"
-        :closable="false"
-        show-icon
-      />
-    </div>
   </div>
   </div>
 </template>
 </template>
 
 
@@ -229,5 +252,3 @@ onMounted(() => {
   }
   }
 })
 })
 </script>
 </script>
-
-

+ 88 - 45
src/views/iot/rule/scene/form/configs/DeviceTriggerConfig.vue

@@ -1,4 +1,4 @@
-<!-- 设备触发配置组件 -->
+<!-- 设备触发配置组件 - 优化版本 -->
 <template>
 <template>
   <div class="flex flex-col gap-16px">
   <div class="flex flex-col gap-16px">
     <!-- 产品和设备选择 -->
     <!-- 产品和设备选择 -->
@@ -16,6 +16,12 @@
           <el-tag size="small" type="info">
           <el-tag size="small" type="info">
             {{ trigger.conditionGroups?.length || 0 }}个条件组
             {{ trigger.conditionGroups?.length || 0 }}个条件组
           </el-tag>
           </el-tag>
+          <el-tooltip
+            content="条件组之间为'或'关系,满足任意一组即可触发;每个条件组内的条件为'且'关系,需要全部满足"
+            placement="top"
+          >
+            <Icon icon="ep:question-filled" class="text-[var(--el-color-info)] cursor-help" />
+          </el-tooltip>
         </div>
         </div>
         <div class="flex items-center gap-8px">
         <div class="flex items-center gap-8px">
           <el-button
           <el-button
@@ -33,64 +39,101 @@
       <!-- 条件组列表 -->
       <!-- 条件组列表 -->
       <div
       <div
         v-if="trigger.conditionGroups && trigger.conditionGroups.length > 0"
         v-if="trigger.conditionGroups && trigger.conditionGroups.length > 0"
-        class="flex flex-col gap-12px"
+        class="space-y-16px"
       >
       >
-        <div
-          v-for="(group, groupIndex) in trigger.conditionGroups"
-          :key="`group-${groupIndex}`"
-          class="border border-[var(--el-border-color-lighter)] rounded-6px bg-[var(--el-fill-color-blank)]"
-        >
+        <!-- 逻辑关系说明 -->
+        <div v-if="trigger.conditionGroups.length > 1" class="flex items-center justify-center">
+          <div
+            class="flex items-center gap-8px px-12px py-6px bg-blue-50 border border-blue-200 rounded-full text-12px text-blue-600"
+          >
+            <Icon icon="ep:info-filled" />
+            <span>条件组之间为"或"关系,满足任意一组即可触发</span>
+          </div>
+        </div>
+
+        <div class="relative">
           <div
           <div
-            class="flex items-center justify-between p-12px px-16px bg-[var(--el-fill-color-light)] border-b border-[var(--el-border-color-lighter)]"
+            v-for="(group, groupIndex) in trigger.conditionGroups"
+            :key="`group-${groupIndex}`"
+            class="relative"
           >
           >
-            <div class="flex items-center text-14px font-500 text-[var(--el-text-color-primary)]">
-              <span>条件组 {{ groupIndex + 1 }}</span>
-              <!-- TODO @puhui999:不用“且、或”哈。条件组之间,就是或;条件之间就是且 -->
-              <el-tag size="small" type="info" class="ml-8px">条件间为"且"关系</el-tag>
+            <!-- 条件组容器 -->
+            <div
+              class="border-2 border-[var(--el-border-color-lighter)] rounded-8px bg-[var(--el-fill-color-blank)] shadow-sm hover:shadow-md transition-shadow"
+            >
+              <div
+                class="flex items-center justify-between p-16px bg-gradient-to-r from-blue-50 to-indigo-50 border-b border-[var(--el-border-color-lighter)] rounded-t-6px"
+              >
+                <div class="flex items-center gap-12px">
+                  <div
+                    class="flex items-center gap-8px text-16px font-600 text-[var(--el-text-color-primary)]"
+                  >
+                    <div
+                      class="w-24px h-24px bg-blue-500 text-white rounded-full flex items-center justify-center text-12px font-bold"
+                    >
+                      {{ groupIndex + 1 }}
+                    </div>
+                    <span>条件组</span>
+                  </div>
+                  <el-tag size="small" type="success" class="font-500"> 组内条件为"且"关系 </el-tag>
+                </div>
+                <el-button
+                  type="danger"
+                  size="small"
+                  text
+                  @click="removeConditionGroup(groupIndex)"
+                  v-if="trigger.conditionGroups!.length > 1"
+                  class="hover:bg-red-50"
+                >
+                  <Icon icon="ep:delete" />
+                  删除组
+                </el-button>
+              </div>
+
+              <ConditionGroupConfig
+                :model-value="group"
+                @update:model-value="(value) => updateConditionGroup(groupIndex, value)"
+                :trigger-type="trigger.type"
+                :product-id="trigger.productId"
+                :device-id="trigger.deviceId"
+                @validate="(result) => handleGroupValidate(groupIndex, result)"
+              />
             </div>
             </div>
-            <el-button
-              type="danger"
-              size="small"
-              text
-              @click="removeConditionGroup(groupIndex)"
-              v-if="trigger.conditionGroups!.length > 1"
+
+            <!-- 条件组间的"或"连接符 -->
+            <div
+              v-if="groupIndex < trigger.conditionGroups!.length - 1"
+              class="flex items-center justify-center py-12px"
             >
             >
-              <Icon icon="ep:delete" />
-              删除组
-            </el-button>
+              <div class="flex items-center gap-8px">
+                <!-- 连接线 -->
+                <div class="w-32px h-1px bg-orange-300"></div>
+                <!-- 或标签 -->
+                <div class="px-16px py-6px bg-orange-100 border-2 border-orange-300 rounded-full">
+                  <span class="text-14px font-600 text-orange-600">或</span>
+                </div>
+                <!-- 连接线 -->
+                <div class="w-32px h-1px bg-orange-300"></div>
+              </div>
+            </div>
           </div>
           </div>
-
-          <ConditionGroupConfig
-            :model-value="group"
-            @update:model-value="(value) => updateConditionGroup(groupIndex, value)"
-            :trigger-type="trigger.type"
-            :product-id="trigger.productId"
-            :device-id="trigger.deviceId"
-            @validate="(result) => handleGroupValidate(groupIndex, result)"
-          />
         </div>
         </div>
       </div>
       </div>
 
 
       <!-- 空状态 -->
       <!-- 空状态 -->
       <div v-else class="py-40px text-center">
       <div v-else class="py-40px text-center">
         <el-empty description="暂无触发条件">
         <el-empty description="暂无触发条件">
-          <el-button type="primary" @click="addConditionGroup">
-            <Icon icon="ep:plus" />
-            添加第一个条件组
-          </el-button>
+          <template #description>
+            <div class="space-y-8px">
+              <p class="text-[var(--el-text-color-secondary)]">暂无触发条件</p>
+              <p class="text-12px text-[var(--el-text-color-placeholder)]">
+                请使用上方的"添加条件组"按钮来设置触发规则
+              </p>
+            </div>
+          </template>
         </el-empty>
         </el-empty>
       </div>
       </div>
     </div>
     </div>
-
-    <!-- 验证结果 -->
-    <div v-if="validationMessage" class="mt-8px">
-      <el-alert
-        :title="validationMessage"
-        :type="isValid ? 'success' : 'error'"
-        :closable="false"
-        show-icon
-      />
-    </div>
   </div>
   </div>
 </template>
 </template>
 
 
@@ -158,7 +201,7 @@ const addConditionGroup = () => {
 
 
   const newGroup: ConditionGroupFormData = {
   const newGroup: ConditionGroupFormData = {
     conditions: [],
     conditions: [],
-    logicOperator: 'AND'
+    logicOperator: 'AND' // 固定为AND,因为条件组内部条件间为"且"关系
   }
   }
 
 
   trigger.value.conditionGroups.push(newGroup)
   trigger.value.conditionGroups.push(newGroup)