Просмотр исходного кода

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

puhui999 11 месяцев назад
Родитель
Сommit
26a4f0fee1

+ 7 - 0
src/views/iot/rule/scene/form/configs/DeviceTriggerConfig.vue

@@ -7,6 +7,7 @@
         v-model="trigger"
         :trigger-type="trigger.type"
         @validate="handleMainConditionValidate"
+        @trigger-type-change="handleTriggerTypeChange"
       />
     </div>
 
@@ -42,6 +43,7 @@ const props = defineProps<{
 const emit = defineEmits<{
   (e: 'update:modelValue', value: TriggerFormData): void
   (e: 'validate', value: { valid: boolean; message: string }): void
+  (e: 'trigger-type-change', type: number): void
 }>()
 
 const trigger = useVModel(props, 'modelValue', emit)
@@ -83,6 +85,11 @@ const handleMainConditionValidate = (result: { valid: boolean; message: string }
   updateValidationResult()
 }
 
+const handleTriggerTypeChange = (type: number) => {
+  trigger.value.type = type
+  emit('trigger-type-change', type)
+}
+
 // 事件处理
 const handleConditionGroupValidate = () => {
   updateValidationResult()

+ 25 - 41
src/views/iot/rule/scene/form/configs/MainConditionConfig.vue

@@ -1,38 +1,33 @@
 <!-- 主条件配置组件 -->
 <template>
   <div class="flex flex-col gap-16px">
-    <!-- 条件配置提示 -->
-    <div
-      v-if="!modelValue"
-      class="p-16px border-2 border-dashed border-[var(--el-border-color)] rounded-8px text-center"
-    >
-      <div class="flex flex-col items-center gap-12px">
-        <Icon icon="ep:plus" class="text-32px text-[var(--el-text-color-placeholder)]" />
-        <div class="text-[var(--el-text-color-secondary)]">
-          <p class="text-14px font-500 mb-4px">请配置主条件</p>
-          <p class="text-12px">主条件是触发器的核心条件,必须满足才能触发场景</p>
-        </div>
-        <el-button type="primary" @click="addMainCondition">
-          <Icon icon="ep:plus" />
-          添加主条件
-        </el-button>
-      </div>
-    </div>
-
     <!-- 主条件配置 -->
     <!-- TODO @puhui999:和“主条件”,是不是和“附加条件组”弄成一个风格,都是占一行;有个绿条; -->
-    <div v-else class="space-y-16px">
-      <div class="flex items-center justify-between">
-        <div class="flex items-center gap-8px">
-          <span class="text-14px font-500 text-[var(--el-text-color-primary)]">主条件</span>
-          <el-tag size="small" type="primary">必须满足</el-tag>
+    <div class="space-y-16px">
+      <!-- 主条件头部 - 与附加条件组保持一致的绿色风格 -->
+      <div
+        class="flex items-center justify-between p-16px bg-gradient-to-r from-green-50 to-emerald-50 border border-green-200 rounded-8px"
+      >
+        <div class="flex items-center gap-12px">
+          <div class="flex items-center gap-8px text-16px font-600 text-green-700">
+            <div
+              class="w-24px h-24px bg-green-500 text-white rounded-full flex items-center justify-center text-12px font-bold"
+            >
+              主
+            </div>
+            <span>主条件</span>
+          </div>
+          <el-tag size="small" type="success">必须满足</el-tag>
         </div>
       </div>
+
+      <!-- 主条件内容配置 -->
       <MainConditionInnerConfig
         :model-value="modelValue"
         @update:model-value="updateCondition"
         :trigger-type="triggerType"
         @validate="handleValidate"
+        @trigger-type-change="handleTriggerTypeChange"
       />
     </div>
   </div>
@@ -45,29 +40,18 @@ import { IotRuleSceneTriggerConditionTypeEnum } from '@/views/iot/utils/constant
 /** 主条件配置组件 */
 defineOptions({ name: 'MainConditionConfig' })
 
-defineProps<{
-  modelValue?: TriggerFormData
+const props = defineProps<{
+  modelValue: TriggerFormData
   triggerType: number
 }>()
 
 const emit = defineEmits<{
-  (e: 'update:modelValue', value?: TriggerFormData): void
+  (e: 'update:modelValue', value: TriggerFormData): void
   (e: 'validate', result: { valid: boolean; message: string }): void
+  (e: 'trigger-type-change', type: number): void
 }>()
 
 // 事件处理
-const addMainCondition = () => {
-  const newCondition: TriggerFormData = {
-    type: IotRuleSceneTriggerConditionTypeEnum.DEVICE_PROPERTY, // 默认为设备属性
-    productId: undefined,
-    deviceId: undefined,
-    identifier: '',
-    operator: '=',
-    value: ''
-  }
-  emit('update:modelValue', newCondition)
-}
-
 const updateCondition = (condition: TriggerFormData) => {
   emit('update:modelValue', condition)
 }
@@ -76,7 +60,7 @@ const handleValidate = (result: { valid: boolean; message: string }) => {
   emit('validate', result)
 }
 
-onMounted(() => {
-  addMainCondition()
-})
+const handleTriggerTypeChange = (type: number) => {
+  emit('trigger-type-change', type)
+}
 </script>

+ 36 - 10
src/views/iot/rule/scene/form/configs/MainConditionInnerConfig.vue

@@ -1,5 +1,23 @@
 <template>
   <div class="space-y-16px">
+    <!-- 触发事件类型选择 -->
+    <el-form-item label="触发事件类型" required>
+      <el-select
+        :model-value="triggerType"
+        @update:model-value="handleTriggerTypeChange"
+        placeholder="请选择触发事件类型"
+        class="w-full"
+        style="width: 100%"
+      >
+        <el-option
+          v-for="option in triggerTypeOptions"
+          :key="option.value"
+          :label="option.label"
+          :value="option.value"
+        />
+      </el-select>
+    </el-form-item>
+
     <!-- 设备属性条件配置 -->
     <div v-if="isDevicePropertyTrigger" class="space-y-16px">
       <!-- 产品设备选择 -->
@@ -57,8 +75,8 @@
         <el-col :span="12">
           <el-form-item label="比较值" required>
             <ValueInput
-              :model-value="condition.param"
-              @update:model-value="(value) => updateConditionField('param', value)"
+              :model-value="condition.value"
+              @update:model-value="(value) => updateConditionField('value', value)"
               :property-type="propertyType"
               :operator="condition.operator"
               :property-config="propertyConfig"
@@ -97,21 +115,22 @@ import PropertySelector from '../selectors/PropertySelector.vue'
 import OperatorSelector from '../selectors/OperatorSelector.vue'
 import ValueInput from '../inputs/ValueInput.vue'
 import DeviceStatusConditionConfig from './DeviceStatusConditionConfig.vue'
-import { ConditionFormData } from '@/api/iot/rule/scene/scene.types'
-import { IotRuleSceneTriggerTypeEnum } from '@/views/iot/utils/constants'
+import { TriggerFormData } from '@/api/iot/rule/scene/scene.types'
+import { IotRuleSceneTriggerTypeEnum, getTriggerTypeOptions } from '@/views/iot/utils/constants'
 import { useVModel } from '@vueuse/core'
 
 /** 主条件内部配置组件 */
 defineOptions({ name: 'MainConditionInnerConfig' })
 
 const props = defineProps<{
-  modelValue: ConditionFormData
+  modelValue: TriggerFormData
   triggerType: number
 }>()
 
 const emit = defineEmits<{
-  (e: 'update:modelValue', value: ConditionFormData): void
+  (e: 'update:modelValue', value: TriggerFormData): void
   (e: 'validate', result: { valid: boolean; message: string }): void
+  (e: 'trigger-type-change', value: number): void
 }>()
 
 // 响应式数据
@@ -152,17 +171,24 @@ const getTriggerTypeText = (type: number) => {
   }
 }
 
+// 触发器类型选项
+const triggerTypeOptions = getTriggerTypeOptions()
+
 // 事件处理
-const updateConditionField = (field: keyof ConditionFormData, value: any) => {
+const updateConditionField = (field: keyof TriggerFormData, value: any) => {
   condition.value[field] = value
   updateValidationResult()
 }
 
-const updateCondition = (value: ConditionFormData) => {
+const updateCondition = (value: TriggerFormData) => {
   emit('update:modelValue', value)
   updateValidationResult()
 }
 
+const handleTriggerTypeChange = (type: number) => {
+  emit('trigger-type-change', type)
+}
+
 const handleProductChange = () => {
   // 产品变化时清空设备和属性
   condition.value.deviceId = undefined
@@ -231,7 +257,7 @@ const updateValidationResult = () => {
       return
     }
 
-    if (!condition.value.param) {
+    if (!condition.value.value) {
       isValid.value = false
       validationMessage.value = '请输入比较值'
       emit('validate', { valid: false, message: validationMessage.value })
@@ -251,7 +277,7 @@ watch(
     condition.value.deviceId,
     condition.value.identifier,
     condition.value.operator,
-    condition.value.param
+    condition.value.value
   ],
   () => {
     updateValidationResult()

+ 34 - 40
src/views/iot/rule/scene/form/sections/TriggerSection.vue

@@ -16,20 +16,26 @@
 
     <div class="p-16px space-y-24px">
       <!-- 触发器列表 -->
-      <!-- TODO 每个触发器,有个外框,会不会好点? -->
       <div v-if="triggers.length > 0" class="space-y-24px">
         <div
           v-for="(triggerItem, index) in triggers"
           :key="`trigger-${index}`"
-          class="border border-[var(--el-border-color-light)] rounded-8px p-16px relative"
+          class="border-2 border-green-200 rounded-8px bg-green-50 shadow-sm hover:shadow-md transition-shadow"
         >
-          <!-- 触发器头部 -->
-          <div class="flex items-center justify-between mb-16px">
-            <div class="flex items-center gap-8px">
-              <span class="text-14px font-500 text-[var(--el-text-color-primary)]">
-                触发器 {{ index + 1 }}
-              </span>
-              <el-tag size="small" :type="getTriggerTagType(triggerItem.type)">
+          <!-- 触发器头部 - 绿色主题 -->
+          <div
+            class="flex items-center justify-between p-16px bg-gradient-to-r from-green-50 to-emerald-50 border-b border-green-200 rounded-t-6px"
+          >
+            <div class="flex items-center gap-12px">
+              <div class="flex items-center gap-8px text-16px font-600 text-green-700">
+                <div
+                  class="w-24px h-24px bg-green-500 text-white rounded-full flex items-center justify-center text-12px font-bold"
+                >
+                  {{ index + 1 }}
+                </div>
+                <span>触发器 {{ index + 1 }}</span>
+              </div>
+              <el-tag size="small" :type="getTriggerTagType(triggerItem.type)" class="font-500">
                 {{ getTriggerTypeLabel(triggerItem.type) }}
               </el-tag>
             </div>
@@ -40,6 +46,7 @@
                 size="small"
                 text
                 @click="removeTrigger(index)"
+                class="hover:bg-red-50"
               >
                 <Icon icon="ep:delete" />
                 删除
@@ -47,37 +54,24 @@
             </div>
           </div>
 
-          <!-- 触发事件类型选择 -->
-          <el-form-item label="触发事件类型" required>
-            <el-select
-              :model-value="triggerItem.type"
-              @update:model-value="(value) => updateTriggerType(index, value)"
-              placeholder="请选择触发事件类型"
-              class="w-full"
-            >
-              <el-option
-                v-for="option in triggerTypeOptions"
-                :key="option.value"
-                :label="option.label"
-                :value="option.value"
-              />
-            </el-select>
-          </el-form-item>
-
-          <!-- 设备触发配置 -->
-          <DeviceTriggerConfig
-            v-if="isDeviceTrigger(triggerItem.type)"
-            :model-value="triggerItem"
-            :index="index"
-            @update:model-value="(value) => updateTriggerDeviceConfig(index, value)"
-          />
-
-          <!-- 定时触发配置 -->
-          <TimerTriggerConfig
-            v-else-if="triggerItem.type === TriggerTypeEnum.TIMER"
-            :model-value="triggerItem.cronExpression"
-            @update:model-value="(value) => updateTriggerCronConfig(index, value)"
-          />
+          <!-- 触发器内容区域 -->
+          <div class="p-16px space-y-16px">
+            <!-- 设备触发配置 -->
+            <DeviceTriggerConfig
+              v-if="isDeviceTrigger(triggerItem.type)"
+              :model-value="triggerItem"
+              :index="index"
+              @update:model-value="(value) => updateTriggerDeviceConfig(index, value)"
+              @trigger-type-change="(type) => updateTriggerType(index, type)"
+            />
+
+            <!-- 定时触发配置 -->
+            <TimerTriggerConfig
+              v-else-if="triggerItem.type === TriggerTypeEnum.TIMER"
+              :model-value="triggerItem.cronExpression"
+              @update:model-value="(value) => updateTriggerCronConfig(index, value)"
+            />
+          </div>
         </div>
       </div>