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

review:【IoT 物联网】场景联动的部分 review

YunaiV 10 месяцев назад
Родитель
Сommit
bbd38e026b
23 измененных файлов с 383 добавлено и 397 удалено
  1. 5 2
      src/views/iot/rule/scene/components/RuleSceneForm.vue
  2. 12 7
      src/views/iot/rule/scene/components/configs/AlertConfig.vue
  3. 18 13
      src/views/iot/rule/scene/components/configs/ConditionConfig.vue
  4. 32 38
      src/views/iot/rule/scene/components/configs/ConditionGroupConfig.vue
  5. 14 14
      src/views/iot/rule/scene/components/configs/DeviceControlConfig.vue
  6. 40 40
      src/views/iot/rule/scene/components/configs/DeviceTriggerConfig.vue
  7. 2 5
      src/views/iot/rule/scene/components/configs/TimerTriggerConfig.vue
  8. 24 15
      src/views/iot/rule/scene/components/inputs/CronBuilder.vue
  9. 10 11
      src/views/iot/rule/scene/components/inputs/CronInput.vue
  10. 10 18
      src/views/iot/rule/scene/components/inputs/DescriptionInput.vue
  11. 8 4
      src/views/iot/rule/scene/components/inputs/NameInput.vue
  12. 33 24
      src/views/iot/rule/scene/components/inputs/ValueInput.vue
  13. 1 0
      src/views/iot/rule/scene/components/previews/ConfigPreview.vue
  14. 24 42
      src/views/iot/rule/scene/components/sections/ActionSection.vue
  15. 3 0
      src/views/iot/rule/scene/components/sections/BasicInfoSection.vue
  16. 3 7
      src/views/iot/rule/scene/components/sections/PreviewSection.vue
  17. 24 34
      src/views/iot/rule/scene/components/sections/TriggerSection.vue
  18. 1 0
      src/views/iot/rule/scene/components/selectors/ActionTypeSelector.vue
  19. 13 11
      src/views/iot/rule/scene/components/selectors/OperatorSelector.vue
  20. 42 36
      src/views/iot/rule/scene/components/selectors/ProductDeviceSelector.vue
  21. 40 36
      src/views/iot/rule/scene/components/selectors/PropertySelector.vue
  22. 11 31
      src/views/iot/rule/scene/components/selectors/TriggerTypeSelector.vue
  23. 13 9
      src/views/iot/rule/scene/index.vue

+ 5 - 2
src/views/iot/rule/scene/components/RuleSceneForm.vue

@@ -1,4 +1,5 @@
 <!-- IoT场景联动规则表单 - 主表单组件 -->
+<!-- TODO @puhui999:要不搞个 form 目录,不用 components;保持和别的模块风格一致哈; -->
 <template>
   <el-drawer
     v-model="drawerVisible"
@@ -37,6 +38,7 @@
     </div>
 
     <!-- 抽屉底部操作栏 -->
+    <!-- TODO @puhui999:这个按钮逻辑,和别的模块一致 -->
     <template #footer>
       <div class="drawer-footer">
         <el-button @click="handleClose" size="large">取消</el-button>
@@ -65,7 +67,7 @@ import { getBaseValidationRules } from '../utils/validation'
 import { transformFormToApi, transformApiToForm, createDefaultFormData } from '../utils/transform'
 import { handleValidationError, showSuccess, withErrorHandling } from '../utils/errorHandler'
 
-/** IoT场景联动规则表单 - 主表单组件 */
+/** IoT 场景联动规则表单 - 主表单组件 */
 defineOptions({ name: 'RuleSceneForm' })
 
 interface Props {
@@ -96,7 +98,7 @@ const actionValidation = ref({ valid: true, message: '' })
 
 // 计算属性
 const isEdit = computed(() => !!props.ruleScene?.id)
-const drawerTitle = computed(() => (isEdit.value ? '编辑场景联动规则' : '新增场景联动规则'))
+const drawerTitle = computed(() => (isEdit.value ? '编辑场景联动规则' : '新增场景联动规则')) // TODO @puhui999:这个风格,和别的模块一致;
 
 const canSubmit = computed(() => {
   return (
@@ -140,6 +142,7 @@ const handleValidate = async () => {
   }
 }
 
+// TODO @puhui999:参考下别的模块,不用这么复杂哈;
 const handleSubmit = async () => {
   const result = await withErrorHandling(
     async () => {

+ 12 - 7
src/views/iot/rule/scene/components/configs/AlertConfig.vue

@@ -1,6 +1,7 @@
 <!-- 告警配置组件 -->
 <template>
   <div class="alert-config">
+    <!-- TODO @puhui999:触发告警时,不用选择配置哈; -->
     <el-form-item label="告警配置" required>
       <el-select
         v-model="localValue"
@@ -95,7 +96,7 @@ const isValid = ref(true)
 
 // 计算属性
 const selectedConfig = computed(() => {
-  return alertConfigs.value.find(config => config.id === localValue.value)
+  return alertConfigs.value.find((config) => config.id === localValue.value)
 })
 
 // 工具函数
@@ -121,7 +122,7 @@ const updateValidationResult = () => {
     emit('validate', { valid: false, message: validationMessage.value })
     return
   }
-  
+
   const config = selectedConfig.value
   if (!config) {
     isValid.value = false
@@ -129,14 +130,14 @@ const updateValidationResult = () => {
     emit('validate', { valid: false, message: validationMessage.value })
     return
   }
-  
+
   if (!config.enabled) {
     isValid.value = false
     validationMessage.value = '选择的告警配置已禁用'
     emit('validate', { valid: false, message: validationMessage.value })
     return
   }
-  
+
   // 验证通过
   isValid.value = true
   validationMessage.value = '告警配置验证通过'
@@ -149,6 +150,7 @@ const getAlertConfigs = async () => {
   try {
     // 这里应该调用真实的API获取告警配置
     // 暂时使用模拟数据
+    // TODO @puhui999:这里是模拟数据
     alertConfigs.value = [
       {
         id: 1,
@@ -183,9 +185,12 @@ const getAlertConfigs = async () => {
 }
 
 // 监听值变化
-watch(() => localValue.value, () => {
-  updateValidationResult()
-})
+watch(
+  () => localValue.value,
+  () => {
+    updateValidationResult()
+  }
+)
 
 // 初始化
 onMounted(() => {

+ 18 - 13
src/views/iot/rule/scene/components/configs/ConditionConfig.vue

@@ -1,4 +1,5 @@
 <!-- 单个条件配置组件 -->
+<!-- TODO @puhui999:这里需要在对下阿里云 IoT,不太对;它是条件类型;然后选择产品、设备;接着选条件类型对应的比较; -->
 <template>
   <div class="condition-config">
     <el-row :gutter="16">
@@ -105,11 +106,11 @@ const conditionPreview = computed(() => {
   if (!condition.value.identifier || !condition.value.operator || !condition.value.param) {
     return ''
   }
-  
+
   const propertyName = propertyConfig.value?.name || condition.value.identifier
   const operatorText = getOperatorText(condition.value.operator)
   const value = condition.value.param
-  
+
   return `当 ${propertyName} ${operatorText} ${value} 时触发`
 })
 
@@ -122,8 +123,8 @@ const getOperatorText = (operator: string) => {
     '>=': '大于等于',
     '<': '小于',
     '<=': '小于等于',
-    'in': '包含于',
-    'between': '介于'
+    in: '包含于',
+    between: '介于'
   }
   return operatorMap[operator] || operator
 }
@@ -137,11 +138,11 @@ const updateConditionField = (field: keyof ConditionFormData, value: any) => {
 const handlePropertyChange = (propertyInfo: { type: string; config: any }) => {
   propertyType.value = propertyInfo.type
   propertyConfig.value = propertyInfo.config
-  
+
   // 重置操作符和值
   condition.value.operator = '='
   condition.value.param = ''
-  
+
   updateValidationResult()
 }
 
@@ -164,21 +165,21 @@ const updateValidationResult = () => {
     emit('validate', { valid: false, message: validationMessage.value })
     return
   }
-  
+
   if (!condition.value.operator) {
     isValid.value = false
     validationMessage.value = '请选择操作符'
     emit('validate', { valid: false, message: validationMessage.value })
     return
   }
-  
+
   if (!condition.value.param) {
     isValid.value = false
     validationMessage.value = '请输入比较值'
     emit('validate', { valid: false, message: validationMessage.value })
     return
   }
-  
+
   // 值验证
   if (!valueValidation.value.valid) {
     isValid.value = false
@@ -186,7 +187,7 @@ const updateValidationResult = () => {
     emit('validate', { valid: false, message: validationMessage.value })
     return
   }
-  
+
   // 验证通过
   isValid.value = true
   validationMessage.value = '条件配置验证通过'
@@ -194,9 +195,13 @@ const updateValidationResult = () => {
 }
 
 // 监听条件变化
-watch(() => [condition.value.identifier, condition.value.operator, condition.value.param], () => {
-  updateValidationResult()
-}, { deep: true })
+watch(
+  () => [condition.value.identifier, condition.value.operator, condition.value.param],
+  () => {
+    updateValidationResult()
+  },
+  { deep: true }
+)
 
 // 初始化
 onMounted(() => {

+ 32 - 38
src/views/iot/rule/scene/components/configs/ConditionGroupConfig.vue

@@ -40,15 +40,9 @@
           </div>
 
           <!-- 逻辑连接符 -->
-          <div
-            v-if="index < group.conditions!.length - 1"
-            class="logic-connector"
-          >
-            <el-select
-              v-model="group.logicOperator"
-              size="small"
-              style="width: 80px;"
-            >
+          <!-- TODO @puhui999:不用这个哈; -->
+          <div v-if="index < group.conditions!.length - 1" class="logic-connector">
+            <el-select v-model="group.logicOperator" size="small" style="width: 80px">
               <el-option label="且" value="AND" />
               <el-option label="或" value="OR" />
             </el-select>
@@ -67,23 +61,22 @@
       </div>
 
       <!-- 添加条件按钮 -->
-      <div v-if="group.conditions && group.conditions.length > 0 && group.conditions.length < maxConditions" class="add-condition">
-        <el-button
-          type="primary"
-          plain
-          @click="addCondition"
-          class="add-condition-btn"
-        >
+      <div
+        v-if="
+          group.conditions && group.conditions.length > 0 && group.conditions.length < maxConditions
+        "
+        class="add-condition"
+      >
+        <el-button type="primary" plain @click="addCondition" class="add-condition-btn">
           <Icon icon="ep:plus" />
           继续添加条件
         </el-button>
-        <span class="add-condition-text">
-          最多可添加 {{ maxConditions }} 个条件
-        </span>
+        <span class="add-condition-text"> 最多可添加 {{ maxConditions }} 个条件 </span>
       </div>
     </div>
 
     <!-- 验证结果 -->
+    <!-- TODO @puhui999:是不是不用这种提示;只要 validator rules 能展示出来就好了呀。。。 -->
     <div v-if="validationMessage" class="validation-result">
       <el-alert
         :title="validationMessage"
@@ -98,10 +91,10 @@
 <script setup lang="ts">
 import { useVModel } from '@vueuse/core'
 import ConditionConfig from './ConditionConfig.vue'
-import { 
-  ConditionGroupFormData, 
+import {
+  ConditionGroupFormData,
   ConditionFormData,
-  IotRuleSceneTriggerTypeEnum 
+  IotRuleSceneTriggerTypeEnum
 } from '@/api/iot/rule/scene/scene.types'
 
 /** 条件组配置组件 */
@@ -155,11 +148,11 @@ const addCondition = () => {
   if (!group.value.conditions) {
     group.value.conditions = []
   }
-  
+
   if (group.value.conditions.length >= maxConditions) {
     return
   }
-  
+
   const newCondition: ConditionFormData = {
     type: props.triggerType,
     productId: props.productId || 0,
@@ -168,7 +161,7 @@ const addCondition = () => {
     operator: '=',
     param: ''
   }
-  
+
   group.value.conditions.push(newCondition)
 }
 
@@ -176,10 +169,10 @@ const removeCondition = (index: number) => {
   if (group.value.conditions) {
     group.value.conditions.splice(index, 1)
     delete conditionValidations.value[index]
-    
+
     // 重新索引验证结果
     const newValidations: { [key: number]: { valid: boolean; message: string } } = {}
-    Object.keys(conditionValidations.value).forEach(key => {
+    Object.keys(conditionValidations.value).forEach((key) => {
       const numKey = parseInt(key)
       if (numKey > index) {
         newValidations[numKey - 1] = conditionValidations.value[numKey]
@@ -188,7 +181,7 @@ const removeCondition = (index: number) => {
       }
     })
     conditionValidations.value = newValidations
-    
+
     updateValidationResult()
   }
 }
@@ -205,28 +198,29 @@ const updateValidationResult = () => {
     emit('validate', { valid: false, message: validationMessage.value })
     return
   }
-  
+
   const validations = Object.values(conditionValidations.value)
-  const allValid = validations.every(v => v.valid)
-  
+  const allValid = validations.every((v) => v.valid)
+
   if (allValid) {
     isValid.value = true
     validationMessage.value = '条件组配置验证通过'
   } else {
     isValid.value = false
-    const errorMessages = validations
-      .filter(v => !v.valid)
-      .map(v => v.message)
+    const errorMessages = validations.filter((v) => !v.valid).map((v) => v.message)
     validationMessage.value = `条件配置错误: ${errorMessages.join('; ')}`
   }
-  
+
   emit('validate', { valid: isValid.value, message: validationMessage.value })
 }
 
 // 监听条件数量变化
-watch(() => group.value.conditions?.length, () => {
-  updateValidationResult()
-})
+watch(
+  () => group.value.conditions?.length,
+  () => {
+    updateValidationResult()
+  }
+)
 
 // 初始化
 onMounted(() => {

+ 14 - 14
src/views/iot/rule/scene/components/configs/DeviceControlConfig.vue

@@ -1,4 +1,5 @@
 <!-- 设备控制配置组件 -->
+<!-- TODO @puhui999:貌似没生效~~~ -->
 <template>
   <div class="device-control-config">
     <!-- 产品和设备选择 -->
@@ -19,15 +20,10 @@
           @input="handleParamsChange"
         />
       </el-form-item>
-      
+
       <!-- 参数示例 -->
       <div class="params-example">
-        <el-alert
-          title="参数格式示例"
-          type="info"
-          :closable="false"
-          show-icon
-        >
+        <el-alert title="参数格式示例" type="info" :closable="false" show-icon>
           <template #default>
             <div class="example-content">
               <p>属性设置示例:</p>
@@ -109,14 +105,14 @@ const updateValidationResult = () => {
     emit('validate', { valid: false, message: validationMessage.value })
     return
   }
-  
+
   if (!action.value.params || Object.keys(action.value.params).length === 0) {
     isValid.value = false
     validationMessage.value = '请配置控制参数'
     emit('validate', { valid: false, message: validationMessage.value })
     return
   }
-  
+
   // 验证通过
   isValid.value = true
   validationMessage.value = '设备控制配置验证通过'
@@ -132,11 +128,15 @@ onMounted(() => {
 })
 
 // 监听参数变化
-watch(() => action.value.params, (newParams) => {
-  if (newParams && typeof newParams === 'object') {
-    paramsJson.value = JSON.stringify(newParams, null, 2)
-  }
-}, { deep: true })
+watch(
+  () => action.value.params,
+  (newParams) => {
+    if (newParams && typeof newParams === 'object') {
+      paramsJson.value = JSON.stringify(newParams, null, 2)
+    }
+  },
+  { deep: true }
+)
 </script>
 
 <style scoped>

+ 40 - 40
src/views/iot/rule/scene/components/configs/DeviceTriggerConfig.vue

@@ -8,17 +8,10 @@
       @change="handleDeviceChange"
     />
 
+    <!-- TODO @puhui999:这里有点冗余,建议去掉 -->
     <!-- 设备状态变更提示 -->
-    <div
-      v-if="trigger.type === TriggerTypeEnum.DEVICE_STATE_UPDATE"
-      class="state-update-notice"
-    >
-      <el-alert
-        title="设备状态变更触发"
-        type="info"
-        :closable="false"
-        show-icon
-      >
+    <div v-if="trigger.type === TriggerTypeEnum.DEVICE_STATE_UPDATE" class="state-update-notice">
+      <el-alert title="设备状态变更触发" type="info" :closable="false" show-icon>
         <template #default>
           <p>当选中的设备上线或离线时将自动触发场景规则</p>
           <p class="notice-tip">无需配置额外的触发条件</p>
@@ -27,13 +20,11 @@
     </div>
 
     <!-- 条件组配置 -->
-    <div
-      v-else-if="needsConditions"
-      class="condition-groups"
-    >
+    <div v-else-if="needsConditions" class="condition-groups">
       <div class="condition-groups-header">
         <div class="header-left">
           <span class="header-title">触发条件</span>
+          <!-- TODO @puhui999:去掉数量限制 -->
           <el-tag size="small" type="info">
             {{ trigger.conditionGroups?.length || 0 }}/{{ maxConditionGroups }}
           </el-tag>
@@ -52,7 +43,10 @@
       </div>
 
       <!-- 条件组列表 -->
-      <div v-if="trigger.conditionGroups && trigger.conditionGroups.length > 0" class="condition-groups-list">
+      <div
+        v-if="trigger.conditionGroups && trigger.conditionGroups.length > 0"
+        class="condition-groups-list"
+      >
         <div
           v-for="(group, groupIndex) in trigger.conditionGroups"
           :key="`group-${groupIndex}`"
@@ -61,10 +55,11 @@
           <div class="group-header">
             <div class="group-title">
               <span>条件组 {{ groupIndex + 1 }}</span>
+              <!-- TODO @puhui999:不用“且、或”哈。条件组之间,就是或;条件之间就是且 -->
               <el-select
                 v-model="group.logicOperator"
                 size="small"
-                style="width: 80px; margin-left: 12px;"
+                style="width: 80px; margin-left: 12px"
               >
                 <el-option label="且" value="AND" />
                 <el-option label="或" value="OR" />
@@ -120,10 +115,10 @@
 import { useVModel } from '@vueuse/core'
 import ProductDeviceSelector from '../selectors/ProductDeviceSelector.vue'
 import ConditionGroupConfig from './ConditionGroupConfig.vue'
-import { 
-  TriggerFormData, 
+import {
+  TriggerFormData,
   ConditionGroupFormData,
-  IotRuleSceneTriggerTypeEnum as TriggerTypeEnum 
+  IotRuleSceneTriggerTypeEnum as TriggerTypeEnum
 } from '@/api/iot/rule/scene/scene.types'
 
 /** 设备触发配置组件 */
@@ -173,16 +168,16 @@ const addConditionGroup = () => {
   if (!trigger.value.conditionGroups) {
     trigger.value.conditionGroups = []
   }
-  
+
   if (trigger.value.conditionGroups.length >= maxConditionGroups) {
     return
   }
-  
+
   const newGroup: ConditionGroupFormData = {
     conditions: [],
     logicOperator: 'AND'
   }
-  
+
   trigger.value.conditionGroups.push(newGroup)
 }
 
@@ -190,10 +185,10 @@ const removeConditionGroup = (index: number) => {
   if (trigger.value.conditionGroups) {
     trigger.value.conditionGroups.splice(index, 1)
     delete groupValidations.value[index]
-    
+
     // 重新索引验证结果
     const newValidations: { [key: number]: { valid: boolean; message: string } } = {}
-    Object.keys(groupValidations.value).forEach(key => {
+    Object.keys(groupValidations.value).forEach((key) => {
       const numKey = parseInt(key)
       if (numKey > index) {
         newValidations[numKey - 1] = groupValidations.value[numKey]
@@ -202,7 +197,7 @@ const removeConditionGroup = (index: number) => {
       }
     })
     groupValidations.value = newValidations
-    
+
     updateValidationResult()
   }
 }
@@ -220,7 +215,7 @@ const updateValidationResult = () => {
     emit('validate', { valid: false, message: validationMessage.value })
     return
   }
-  
+
   // 设备状态变更不需要条件验证
   if (trigger.value.type === TriggerTypeEnum.DEVICE_STATE_UPDATE) {
     isValid.value = true
@@ -228,7 +223,7 @@ const updateValidationResult = () => {
     emit('validate', { valid: true, message: validationMessage.value })
     return
   }
-  
+
   // 条件组验证
   if (!trigger.value.conditionGroups || trigger.value.conditionGroups.length === 0) {
     isValid.value = false
@@ -236,33 +231,38 @@ const updateValidationResult = () => {
     emit('validate', { valid: false, message: validationMessage.value })
     return
   }
-  
+
   const validations = Object.values(groupValidations.value)
-  const allValid = validations.every(v => v.valid)
-  
+  const allValid = validations.every((v) => v.valid)
+
   if (allValid) {
     isValid.value = true
     validationMessage.value = '设备触发配置验证通过'
   } else {
     isValid.value = false
-    const errorMessages = validations
-      .filter(v => !v.valid)
-      .map(v => v.message)
+    const errorMessages = validations.filter((v) => !v.valid).map((v) => v.message)
     validationMessage.value = `条件组配置错误: ${errorMessages.join('; ')}`
   }
-  
+
   emit('validate', { valid: isValid.value, message: validationMessage.value })
 }
 
 // 监听触发器类型变化
-watch(() => trigger.value.type, () => {
-  updateValidationResult()
-})
+watch(
+  () => trigger.value.type,
+  () => {
+    updateValidationResult()
+  }
+)
 
 // 监听产品设备变化
-watch(() => [trigger.value.productId, trigger.value.deviceId], () => {
-  updateValidationResult()
-})
+watch(
+  () => [trigger.value.productId, trigger.value.deviceId],
+  () => {
+    updateValidationResult()
+  }
+)
+// TODO @puhui999:unocss
 </script>
 
 <style scoped>

+ 2 - 5
src/views/iot/rule/scene/components/configs/TimerTriggerConfig.vue

@@ -7,11 +7,7 @@
         <span class="header-title">定时触发配置</span>
       </div>
       <div class="header-right">
-        <el-button
-          type="text"
-          size="small"
-          @click="showBuilder = !showBuilder"
-        >
+        <el-button type="text" size="small" @click="showBuilder = !showBuilder">
           <Icon :icon="showBuilder ? 'ep:edit' : 'ep:setting'" />
           {{ showBuilder ? '手动编辑' : '可视化编辑' }}
         </el-button>
@@ -19,6 +15,7 @@
     </div>
 
     <!-- 可视化编辑器 -->
+    <!-- TODO @puhui999:是不是复用现有的 cron 组件;不然有点重复哈;维护比较复杂 -->
     <div v-if="showBuilder" class="visual-builder">
       <CronBuilder v-model="localValue" @validate="handleValidate" />
     </div>

+ 24 - 15
src/views/iot/rule/scene/components/inputs/CronBuilder.vue

@@ -1,10 +1,11 @@
 <!-- CRON 可视化构建器组件 -->
+<!-- TODO @puhui999:看看能不能复用全局的 cron 组件 -->
 <template>
   <div class="cron-builder">
     <div class="builder-header">
       <span class="header-title">可视化 CRON 编辑器</span>
     </div>
-    
+
     <div class="builder-content">
       <!-- 快捷选项 -->
       <div class="quick-options">
@@ -36,9 +37,9 @@
                 <el-option label="每分钟" value="*" />
                 <el-option
                   v-for="i in 60"
-                  :key="i-1"
-                  :label="`${i-1}分`"
-                  :value="String(i-1)"
+                  :key="i - 1"
+                  :label="`${i - 1}分`"
+                  :value="String(i - 1)"
                 />
               </el-select>
             </el-form-item>
@@ -49,9 +50,9 @@
                 <el-option label="每小时" value="*" />
                 <el-option
                   v-for="i in 24"
-                  :key="i-1"
-                  :label="`${i-1}时`"
-                  :value="String(i-1)"
+                  :key="i - 1"
+                  :label="`${i - 1}时`"
+                  :value="String(i - 1)"
                 />
               </el-select>
             </el-form-item>
@@ -60,12 +61,7 @@
             <el-form-item label="日">
               <el-select v-model="cronParts.day" @change="updateCronExpression">
                 <el-option label="每日" value="*" />
-                <el-option
-                  v-for="i in 31"
-                  :key="i"
-                  :label="`${i}日`"
-                  :value="String(i)"
-                />
+                <el-option v-for="i in 31" :key="i" :label="`${i}日`" :value="String(i)" />
               </el-select>
             </el-form-item>
           </el-col>
@@ -132,7 +128,20 @@ const cronParts = reactive({
 })
 
 // 常量数据
-const months = ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月']
+const months = [
+  '1月',
+  '2月',
+  '3月',
+  '4月',
+  '5月',
+  '6月',
+  '7月',
+  '8月',
+  '9月',
+  '10月',
+  '11月',
+  '12月'
+]
 const weeks = ['周日', '周一', '周二', '周三', '周四', '周五', '周六']
 
 // 快捷选项
@@ -159,7 +168,7 @@ const applyQuickOption = (option: any) => {
 
 const parseCronExpression = () => {
   if (!localValue.value) return
-  
+
   const parts = localValue.value.split(' ')
   if (parts.length >= 6) {
     cronParts.second = parts[0] || '0'

+ 10 - 11
src/views/iot/rule/scene/components/inputs/CronInput.vue

@@ -1,4 +1,5 @@
 <!-- CRON 表达式输入组件 -->
+<!-- TODO @puhui999:看看能不能复用全局的 cron 组件 -->
 <template>
   <div class="cron-input">
     <el-input
@@ -13,15 +14,10 @@
         </el-tooltip>
       </template>
     </el-input>
-    
+
     <!-- 帮助信息 -->
     <div v-if="showHelp" class="cron-help">
-      <el-alert
-        title="CRON 表达式格式:秒 分 时 日 月 周"
-        type="info"
-        :closable="false"
-        show-icon
-      >
+      <el-alert title="CRON 表达式格式:秒 分 时 日 月 周" type="info" :closable="false" show-icon>
         <template #default>
           <div class="help-content">
             <p><strong>示例:</strong></p>
@@ -83,7 +79,7 @@ const validateExpression = () => {
     emit('validate', { valid: false, message: '请输入CRON表达式' })
     return
   }
-  
+
   const isValid = validateCronExpression(localValue.value)
   if (isValid) {
     emit('validate', { valid: true, message: 'CRON表达式验证通过' })
@@ -93,9 +89,12 @@ const validateExpression = () => {
 }
 
 // 监听值变化
-watch(() => localValue.value, () => {
-  validateExpression()
-})
+watch(
+  () => localValue.value,
+  () => {
+    validateExpression()
+  }
+)
 
 // 初始化
 onMounted(() => {

+ 10 - 18
src/views/iot/rule/scene/components/inputs/DescriptionInput.vue

@@ -15,19 +15,10 @@
 
     <!-- 描述模板 -->
     <teleport to="body">
-      <div
-        v-if="showTemplates"
-        ref="templateDropdownRef"
-        class="templates"
-        :style="dropdownStyle"
-      >
+      <div v-if="showTemplates" ref="templateDropdownRef" class="templates" :style="dropdownStyle">
         <div class="templates-header">
           <span class="templates-title">描述模板</span>
-          <el-button
-            type="text"
-            size="small"
-            @click="showTemplates = false"
-          >
+          <el-button type="text" size="small" @click="showTemplates = false">
             <Icon icon="ep:close" />
           </el-button>
         </div>
@@ -45,13 +36,10 @@
       </div>
     </teleport>
 
+    <!-- TODO @puhui999:不用模版哈,简单点。。。 -->
     <!-- 模板按钮 -->
     <div v-if="!localValue && !showTemplates" class="template-trigger">
-      <el-button
-        type="text"
-        size="small"
-        @click="toggleTemplates"
-      >
+      <el-button type="text" size="small" @click="toggleTemplates">
         <Icon icon="ep:document" class="mr-1" />
         使用模板
       </el-button>
@@ -163,8 +151,12 @@ const toggleTemplates = () => {
 
 // 点击外部关闭下拉框
 const handleClickOutside = (event: Event) => {
-  if (templateDropdownRef.value && !templateDropdownRef.value.contains(event.target as Node) &&
-      inputRef.value && !inputRef.value.$el.contains(event.target as Node)) {
+  if (
+    templateDropdownRef.value &&
+    !templateDropdownRef.value.contains(event.target as Node) &&
+    inputRef.value &&
+    !inputRef.value.$el.contains(event.target as Node)
+  ) {
     showTemplates.value = false
   }
 }

+ 8 - 4
src/views/iot/rule/scene/components/inputs/NameInput.vue

@@ -14,8 +14,9 @@
         <Icon icon="ep:edit" class="input-icon" />
       </template>
     </el-input>
-    
+
     <!-- 智能提示 -->
+    <!-- TODO @puhui999:暂时不用考虑智能推荐哈。用途不大 -->
     <div v-if="showSuggestions && suggestions.length > 0" class="suggestions">
       <div class="suggestions-header">
         <span class="suggestions-title">推荐名称</span>
@@ -72,9 +73,12 @@ const nameTemplates = [
 const handleInput = (value: string) => {
   if (value.length > 0 && value.length < 10) {
     // 根据输入内容过滤建议
-    suggestions.value = nameTemplates.filter(template => 
-      template.includes(value) || value.includes('温度') && template.includes('温度')
-    ).slice(0, 5)
+    suggestions.value = nameTemplates
+      .filter(
+        (template) =>
+          template.includes(value) || (value.includes('温度') && template.includes('温度'))
+      )
+      .slice(0, 5)
     showSuggestions.value = suggestions.value.length > 0
   } else {
     showSuggestions.value = false

+ 33 - 24
src/views/iot/rule/scene/components/inputs/ValueInput.vue

@@ -1,4 +1,5 @@
 <!-- 值输入组件 -->
+<!-- TODO @yunai:这个需要在看看。。。 -->
 <template>
   <div class="value-input">
     <!-- 布尔值选择 -->
@@ -64,12 +65,7 @@
       </el-input>
       <div v-if="listPreview.length > 0" class="list-preview">
         <span class="preview-label">解析结果:</span>
-        <el-tag
-          v-for="(item, index) in listPreview"
-          :key="index"
-          size="small"
-          class="preview-tag"
-        >
+        <el-tag v-for="(item, index) in listPreview" :key="index" size="small" class="preview-tag">
           {{ item }}
         </el-tag>
       </div>
@@ -110,7 +106,11 @@
       class="w-full"
     >
       <template #suffix>
-        <el-tooltip v-if="propertyConfig?.unit" :content="`单位:${propertyConfig.unit}`" placement="top">
+        <el-tooltip
+          v-if="propertyConfig?.unit"
+          :content="`单位:${propertyConfig.unit}`"
+          placement="top"
+        >
           <span class="input-unit">{{ propertyConfig.unit }}</span>
         </el-tooltip>
       </template>
@@ -172,7 +172,10 @@ const enumOptions = computed(() => {
 
 const listPreview = computed(() => {
   if (props.operator === 'in' && localValue.value) {
-    return localValue.value.split(',').map(item => item.trim()).filter(item => item)
+    return localValue.value
+      .split(',')
+      .map((item) => item.trim())
+      .filter((item) => item)
   }
   return []
 })
@@ -195,12 +198,12 @@ const getInputType = () => {
 
 const getPlaceholder = () => {
   const typeMap = {
-    'string': '请输入字符串',
-    'int': '请输入整数',
-    'float': '请输入浮点数',
-    'double': '请输入双精度数',
-    'struct': '请输入JSON格式数据',
-    'array': '请输入数组格式数据'
+    string: '请输入字符串',
+    int: '请输入整数',
+    float: '请输入浮点数',
+    double: '请输入双精度数',
+    struct: '请输入JSON格式数据',
+    array: '请输入数组格式数据'
   }
   return typeMap[props.propertyType || ''] || '请输入值'
 }
@@ -325,18 +328,24 @@ const validateValue = () => {
 }
 
 // 监听值变化
-watch(() => localValue.value, () => {
-  validateValue()
-})
+watch(
+  () => localValue.value,
+  () => {
+    validateValue()
+  }
+)
 
 // 监听操作符变化
-watch(() => props.operator, () => {
-  localValue.value = ''
-  rangeStart.value = ''
-  rangeEnd.value = ''
-  dateValue.value = ''
-  numberValue.value = undefined
-})
+watch(
+  () => props.operator,
+  () => {
+    localValue.value = ''
+    rangeStart.value = ''
+    rangeEnd.value = ''
+    dateValue.value = ''
+    numberValue.value = undefined
+  }
+)
 
 // 初始化
 onMounted(() => {

+ 1 - 0
src/views/iot/rule/scene/components/previews/ConfigPreview.vue

@@ -1,4 +1,5 @@
 <!-- 配置预览组件 -->
+<!-- TODO @puhui999:应该暂时不用预览哈 -->
 <template>
   <div class="config-preview">
     <div class="preview-items">

+ 24 - 42
src/views/iot/rule/scene/components/sections/ActionSection.vue

@@ -1,4 +1,5 @@
 <!-- 执行器配置组件 -->
+<!-- todo @puhui999:参考“触发器配置”,简化下。 -->
 <template>
   <el-card class="action-section" shadow="never">
     <template #header>
@@ -35,19 +36,12 @@
 
       <!-- 执行器列表 -->
       <div v-else class="actions-list">
-        <div
-          v-for="(action, index) in actions"
-          :key="`action-${index}`"
-          class="action-item"
-        >
+        <div v-for="(action, index) in actions" :key="`action-${index}`" class="action-item">
           <div class="action-header">
             <div class="action-title">
               <Icon icon="ep:setting" class="action-icon" />
               <span>执行器 {{ index + 1 }}</span>
-              <el-tag
-                :type="getActionTypeTag(action.type)"
-                size="small"
-              >
+              <el-tag :type="getActionTypeTag(action.type)" size="small">
                 {{ getActionTypeName(action.type) }}
               </el-tag>
             </div>
@@ -94,18 +88,11 @@
 
       <!-- 添加提示 -->
       <div v-if="actions.length > 0 && actions.length < maxActions" class="add-more">
-        <el-button
-          type="primary"
-          plain
-          @click="addAction"
-          class="add-more-btn"
-        >
+        <el-button type="primary" plain @click="addAction" class="add-more-btn">
           <Icon icon="ep:plus" />
           继续添加执行器
         </el-button>
-        <span class="add-more-text">
-          最多可添加 {{ maxActions }} 个执行器
-        </span>
+        <span class="add-more-text"> 最多可添加 {{ maxActions }} 个执行器 </span>
       </div>
 
       <!-- 验证结果 -->
@@ -126,9 +113,9 @@ import { useVModel } from '@vueuse/core'
 import ActionTypeSelector from '../selectors/ActionTypeSelector.vue'
 import DeviceControlConfig from '../configs/DeviceControlConfig.vue'
 import AlertConfig from '../configs/AlertConfig.vue'
-import { 
-  ActionFormData, 
-  IotRuleSceneActionTypeEnum as ActionTypeEnum 
+import {
+  ActionFormData,
+  IotRuleSceneActionTypeEnum as ActionTypeEnum
 } from '@/api/iot/rule/scene/scene.types'
 import { createDefaultActionData } from '../../utils/transform'
 
@@ -174,17 +161,11 @@ const actionTypeTags = {
 
 // 工具函数
 const isDeviceAction = (type: number) => {
-  return [
-    ActionTypeEnum.DEVICE_PROPERTY_SET,
-    ActionTypeEnum.DEVICE_SERVICE_INVOKE
-  ].includes(type)
+  return [ActionTypeEnum.DEVICE_PROPERTY_SET, ActionTypeEnum.DEVICE_SERVICE_INVOKE].includes(type)
 }
 
 const isAlertAction = (type: number) => {
-  return [
-    ActionTypeEnum.ALERT_TRIGGER,
-    ActionTypeEnum.ALERT_RECOVER
-  ].includes(type)
+  return [ActionTypeEnum.ALERT_TRIGGER, ActionTypeEnum.ALERT_RECOVER].includes(type)
 }
 
 const getActionTypeName = (type: number) => {
@@ -200,7 +181,7 @@ const addAction = () => {
   if (actions.value.length >= maxActions) {
     return
   }
-  
+
   const newAction = createDefaultActionData()
   actions.value.push(newAction)
 }
@@ -208,10 +189,10 @@ const addAction = () => {
 const removeAction = (index: number) => {
   actions.value.splice(index, 1)
   delete actionValidations.value[index]
-  
+
   // 重新索引验证结果
   const newValidations: { [key: number]: { valid: boolean; message: string } } = {}
-  Object.keys(actionValidations.value).forEach(key => {
+  Object.keys(actionValidations.value).forEach((key) => {
     const numKey = parseInt(key)
     if (numKey > index) {
       newValidations[numKey - 1] = actionValidations.value[numKey]
@@ -220,7 +201,7 @@ const removeAction = (index: number) => {
     }
   })
   actionValidations.value = newValidations
-  
+
   updateValidationResult()
 }
 
@@ -258,9 +239,9 @@ const handleActionValidate = (index: number, result: { valid: boolean; message:
 
 const updateValidationResult = () => {
   const validations = Object.values(actionValidations.value)
-  const allValid = validations.every(v => v.valid)
+  const allValid = validations.every((v) => v.valid)
   const hasValidations = validations.length > 0
-  
+
   if (!hasValidations) {
     isValid.value = true
     validationMessage.value = ''
@@ -269,19 +250,20 @@ const updateValidationResult = () => {
     validationMessage.value = '所有执行器配置验证通过'
   } else {
     isValid.value = false
-    const errorMessages = validations
-      .filter(v => !v.valid)
-      .map(v => v.message)
+    const errorMessages = validations.filter((v) => !v.valid).map((v) => v.message)
     validationMessage.value = `执行器配置错误: ${errorMessages.join('; ')}`
   }
-  
+
   emit('validate', { valid: isValid.value, message: validationMessage.value })
 }
 
 // 监听执行器数量变化
-watch(() => actions.value.length, () => {
-  updateValidationResult()
-})
+watch(
+  () => actions.value.length,
+  () => {
+    updateValidationResult()
+  }
+)
 </script>
 
 <style scoped>

+ 3 - 0
src/views/iot/rule/scene/components/sections/BasicInfoSection.vue

@@ -17,11 +17,13 @@
 
     <div class="section-content">
       <el-row :gutter="24">
+        <!-- TODO @puhui999:NameInput、StatusRadio、DescriptionInput 是不是直接写在当前界面哈。有点散; -->
         <el-col :span="12">
           <el-form-item label="场景名称" prop="name" required>
             <NameInput v-model="formData.name" />
           </el-form-item>
         </el-col>
+        <!-- TODO @puhui999:每个一行会好点? -->
         <el-col :span="12">
           <el-form-item label="场景状态" prop="status" required>
             <StatusRadio v-model="formData.status" />
@@ -59,6 +61,7 @@ const props = defineProps<Props>()
 const emit = defineEmits<Emits>()
 
 const formData = useVModel(props, 'modelValue', emit)
+// TODO @puhui999:看看能不能 unocss
 </script>
 
 <style scoped>

+ 3 - 7
src/views/iot/rule/scene/components/sections/PreviewSection.vue

@@ -1,4 +1,5 @@
 <!-- 预览区域组件 -->
+<!-- TODO @puhui999:是不是不用这个哈? -->
 <template>
   <el-card class="preview-section" shadow="never">
     <template #header>
@@ -8,12 +9,7 @@
           <span class="section-title">配置预览</span>
         </div>
         <div class="header-right">
-          <el-button
-            type="primary"
-            size="small"
-            @click="handleValidate"
-            :loading="validating"
-          >
+          <el-button type="primary" size="small" @click="handleValidate" :loading="validating">
             <Icon icon="ep:check" />
             验证配置
           </el-button>
@@ -101,7 +97,7 @@ const handleValidate = async () => {
   validating.value = true
   try {
     // 延迟一下模拟验证过程
-    await new Promise(resolve => setTimeout(resolve, 500))
+    await new Promise((resolve) => setTimeout(resolve, 500))
     emit('validate')
   } finally {
     validating.value = false

+ 24 - 34
src/views/iot/rule/scene/components/sections/TriggerSection.vue

@@ -6,6 +6,7 @@
         <div class="header-left">
           <Icon icon="ep:lightning" class="section-icon" />
           <span class="section-title">触发器配置</span>
+          <!-- TODO @puhui999:是不是去掉 maxTriggers;计数 -->
           <el-tag size="small" type="info">{{ triggers.length }}/{{ maxTriggers }}</el-tag>
         </div>
         <div class="header-right">
@@ -26,6 +27,7 @@
       <!-- 空状态 -->
       <div v-if="triggers.length === 0" class="empty-state">
         <el-empty description="暂无触发器配置">
+          <!-- TODO @puhui999:这个要不要去掉哈;入口统一点 -->
           <el-button type="primary" @click="addTrigger">
             <Icon icon="ep:plus" />
             添加第一个触发器
@@ -35,19 +37,12 @@
 
       <!-- 触发器列表 -->
       <div v-else class="triggers-list">
-        <div
-          v-for="(trigger, index) in triggers"
-          :key="`trigger-${index}`"
-          class="trigger-item"
-        >
+        <div v-for="(trigger, index) in triggers" :key="`trigger-${index}`" class="trigger-item">
           <div class="trigger-header">
             <div class="trigger-title">
               <Icon icon="ep:lightning" class="trigger-icon" />
               <span>触发器 {{ index + 1 }}</span>
-              <el-tag
-                :type="getTriggerTypeTag(trigger.type)"
-                size="small"
-              >
+              <el-tag :type="getTriggerTypeTag(trigger.type)" size="small">
                 {{ getTriggerTypeName(trigger.type) }}
               </el-tag>
             </div>
@@ -93,19 +88,13 @@
       </div>
 
       <!-- 添加提示 -->
+      <!-- TODO @puhui999:这个要不要去掉哈;入口统一点 -->
       <div v-if="triggers.length > 0 && triggers.length < maxTriggers" class="add-more">
-        <el-button
-          type="primary"
-          plain
-          @click="addTrigger"
-          class="add-more-btn"
-        >
+        <el-button type="primary" plain @click="addTrigger" class="add-more-btn">
           <Icon icon="ep:plus" />
           继续添加触发器
         </el-button>
-        <span class="add-more-text">
-          最多可添加 {{ maxTriggers }} 个触发器
-        </span>
+        <span class="add-more-text"> 最多可添加 {{ maxTriggers }} 个触发器 </span>
       </div>
 
       <!-- 验证结果 -->
@@ -126,9 +115,9 @@ import { useVModel } from '@vueuse/core'
 import TriggerTypeSelector from '../selectors/TriggerTypeSelector.vue'
 import DeviceTriggerConfig from '../configs/DeviceTriggerConfig.vue'
 import TimerTriggerConfig from '../configs/TimerTriggerConfig.vue'
-import { 
-  TriggerFormData, 
-  IotRuleSceneTriggerTypeEnum as TriggerTypeEnum 
+import {
+  TriggerFormData,
+  IotRuleSceneTriggerTypeEnum as TriggerTypeEnum
 } from '@/api/iot/rule/scene/scene.types'
 import { createDefaultTriggerData } from '../../utils/transform'
 
@@ -197,7 +186,7 @@ const addTrigger = () => {
   if (triggers.value.length >= maxTriggers) {
     return
   }
-  
+
   const newTrigger = createDefaultTriggerData()
   triggers.value.push(newTrigger)
 }
@@ -205,10 +194,10 @@ const addTrigger = () => {
 const removeTrigger = (index: number) => {
   triggers.value.splice(index, 1)
   delete triggerValidations.value[index]
-  
+
   // 重新索引验证结果
   const newValidations: { [key: number]: { valid: boolean; message: string } } = {}
-  Object.keys(triggerValidations.value).forEach(key => {
+  Object.keys(triggerValidations.value).forEach((key) => {
     const numKey = parseInt(key)
     if (numKey > index) {
       newValidations[numKey - 1] = triggerValidations.value[numKey]
@@ -217,7 +206,7 @@ const removeTrigger = (index: number) => {
     }
   })
   triggerValidations.value = newValidations
-  
+
   updateValidationResult()
 }
 
@@ -263,9 +252,9 @@ const handleTriggerValidate = (index: number, result: { valid: boolean; message:
 
 const updateValidationResult = () => {
   const validations = Object.values(triggerValidations.value)
-  const allValid = validations.every(v => v.valid)
+  const allValid = validations.every((v) => v.valid)
   const hasValidations = validations.length > 0
-  
+
   if (!hasValidations) {
     isValid.value = true
     validationMessage.value = ''
@@ -274,19 +263,20 @@ const updateValidationResult = () => {
     validationMessage.value = '所有触发器配置验证通过'
   } else {
     isValid.value = false
-    const errorMessages = validations
-      .filter(v => !v.valid)
-      .map(v => v.message)
+    const errorMessages = validations.filter((v) => !v.valid).map((v) => v.message)
     validationMessage.value = `触发器配置错误: ${errorMessages.join('; ')}`
   }
-  
+
   emit('validate', { valid: isValid.value, message: validationMessage.value })
 }
 
 // 监听触发器数量变化
-watch(() => triggers.value.length, () => {
-  updateValidationResult()
-})
+watch(
+  () => triggers.value.length,
+  () => {
+    updateValidationResult()
+  }
+)
 </script>
 
 <style scoped>

+ 1 - 0
src/views/iot/rule/scene/components/selectors/ActionTypeSelector.vue

@@ -1,6 +1,7 @@
 <!-- 执行器类型选择组件 -->
 <template>
   <div class="action-type-selector">
+    <!-- TODO @puhui999:1)设备属性设置时,貌似没选属性;2)服务调用时,貌似也没的设置哈; -->
     <el-form-item label="执行类型" required>
       <el-select
         v-model="localValue"

+ 13 - 11
src/views/iot/rule/scene/components/selectors/OperatorSelector.vue

@@ -24,6 +24,7 @@
     </el-select>
 
     <!-- 操作符说明 -->
+    <!-- TODO @puhui999:这个去掉 -->
     <div v-if="selectedOperator" class="operator-description">
       <div class="desc-content">
         <Icon icon="ep:info-filled" class="desc-icon" />
@@ -155,14 +156,12 @@ const availableOperators = computed(() => {
   if (!props.propertyType) {
     return allOperators
   }
-  
-  return allOperators.filter(op => 
-    op.supportedTypes.includes(props.propertyType!)
-  )
+
+  return allOperators.filter((op) => op.supportedTypes.includes(props.propertyType!))
 })
 
 const selectedOperator = computed(() => {
-  return allOperators.find(op => op.value === localValue.value)
+  return allOperators.find((op) => op.value === localValue.value)
 })
 
 // 事件处理
@@ -171,14 +170,17 @@ const handleChange = (value: string) => {
 }
 
 // 监听属性类型变化
-watch(() => props.propertyType, () => {
-  // 如果当前选择的操作符不支持新的属性类型,则清空选择
-  if (localValue.value && selectedOperator.value) {
-    if (!selectedOperator.value.supportedTypes.includes(props.propertyType || '')) {
-      localValue.value = ''
+watch(
+  () => props.propertyType,
+  () => {
+    // 如果当前选择的操作符不支持新的属性类型,则清空选择
+    if (localValue.value && selectedOperator.value) {
+      if (!selectedOperator.value.supportedTypes.includes(props.propertyType || '')) {
+        localValue.value = ''
+      }
     }
   }
-})
+)
 </script>
 
 <style scoped>

+ 42 - 36
src/views/iot/rule/scene/components/selectors/ProductDeviceSelector.vue

@@ -25,6 +25,7 @@
                   <div class="option-name">{{ product.name }}</div>
                   <div class="option-key">{{ product.productKey }}</div>
                 </div>
+                <!-- TODO @puhui999:是不是用字典 -->
                 <el-tag size="small" :type="product.status === 0 ? 'success' : 'danger'">
                   {{ product.status === 0 ? '正常' : '禁用' }}
                 </el-tag>
@@ -38,8 +39,8 @@
       <el-col :span="12">
         <el-form-item label="设备选择模式" required>
           <el-radio-group v-model="deviceSelectionMode" @change="handleDeviceSelectionModeChange">
-            <el-radio value="specific">选择设备</el-radio>
             <el-radio value="all">全部设备</el-radio>
+            <el-radio value="specific">选择设备</el-radio>
           </el-radio-group>
         </el-form-item>
       </el-col>
@@ -48,7 +49,9 @@
     <!-- 具体设备选择 -->
     <el-row v-if="deviceSelectionMode === 'specific'" :gutter="16">
       <el-col :span="24">
+        <!-- TODO @puhui999:貌似产品选择不上; -->
         <el-form-item label="选择设备" required>
+          <!-- TODO @puhui999:请先选择产品,是不是改成请选择设备?然后上面,localProductId 为空(未选择)的时候,禁用 deviceSelectionMode -->
           <el-select
             v-model="localDeviceId"
             placeholder="请先选择产品"
@@ -70,10 +73,7 @@
                   <div class="option-name">{{ device.deviceName }}</div>
                   <div class="option-nickname">{{ device.nickname || '无备注' }}</div>
                 </div>
-                <el-tag
-                  size="small"
-                  :type="getDeviceStatusTag(device.state)"
-                >
+                <el-tag size="small" :type="getDeviceStatusTag(device.state)">
                   {{ getDeviceStatusText(device.state) }}
                 </el-tag>
               </div>
@@ -84,7 +84,7 @@
     </el-row>
 
     <!-- 选择结果展示 -->
-    <div v-if="localProductId && (localDeviceId !== undefined)" class="selection-result">
+    <div v-if="localProductId && localDeviceId !== undefined" class="selection-result">
       <div class="result-header">
         <Icon icon="ep:check" class="result-icon" />
         <span class="result-title">已选择设备</span>
@@ -99,18 +99,8 @@
           <span class="result-label">设备:</span>
           <span v-if="deviceSelectionMode === 'all'" class="result-value">全部设备</span>
           <span v-else class="result-value">{{ selectedDevice?.deviceName }}</span>
-          <el-tag
-            v-if="deviceSelectionMode === 'all'"
-            size="small"
-            type="warning"
-          >
-            全部
-          </el-tag>
-          <el-tag
-            v-else
-            size="small"
-            :type="getDeviceStatusTag(selectedDevice?.state)"
-          >
+          <el-tag v-if="deviceSelectionMode === 'all'" size="small" type="warning"> 全部 </el-tag>
+          <el-tag v-else size="small" :type="getDeviceStatusTag(selectedDevice?.state)">
             {{ getDeviceStatusText(selectedDevice?.state) }}
           </el-tag>
         </div>
@@ -145,7 +135,8 @@ const localProductId = useVModel(props, 'productId', emit)
 const localDeviceId = useVModel(props, 'deviceId', emit)
 
 // 设备选择模式
-const deviceSelectionMode = ref<'specific' | 'all'>('specific')
+// TODO @puhui999:默认选中 all
+const deviceSelectionMode = ref<'specific' | 'all'>('all')
 
 // 数据状态
 const productLoading = ref(false)
@@ -155,29 +146,38 @@ const deviceList = ref<any[]>([])
 
 // 计算属性
 const selectedProduct = computed(() => {
-  return productList.value.find(p => p.id === localProductId.value)
+  return productList.value.find((p) => p.id === localProductId.value)
 })
 
 const selectedDevice = computed(() => {
-  return deviceList.value.find(d => d.id === localDeviceId.value)
+  return deviceList.value.find((d) => d.id === localDeviceId.value)
 })
 
+// TODO @puhui999:字典下;
 // 设备状态映射
 const getDeviceStatusText = (state?: number) => {
   switch (state) {
-    case 0: return '未激活'
-    case 1: return '在线'
-    case 2: return '离线'
-    default: return '未知'
+    case 0:
+      return '未激活'
+    case 1:
+      return '在线'
+    case 2:
+      return '离线'
+    default:
+      return '未知'
   }
 }
 
 const getDeviceStatusTag = (state?: number) => {
   switch (state) {
-    case 0: return 'info'
-    case 1: return 'success'
-    case 2: return 'danger'
-    default: return 'info'
+    case 0:
+      return 'info'
+    case 1:
+      return 'success'
+    case 2:
+      return 'danger'
+    default:
+      return 'info'
   }
 }
 
@@ -203,10 +203,10 @@ const handleDeviceSelectionModeChange = (mode: 'specific' | 'all') => {
   deviceSelectionMode.value = mode
 
   if (mode === 'all') {
-    // 全部设备时,设备ID设为0
+    // 全部设备时,设备 ID 设为 0
     localDeviceId.value = 0
   } else {
-    // 选择设备时,清空设备ID
+    // 选择设备时,清空设备 ID
     localDeviceId.value = undefined
   }
 
@@ -229,6 +229,7 @@ const getProductList = async () => {
   } catch (error) {
     console.error('获取产品列表失败:', error)
     // 模拟数据
+    // TODO @puhui999:移除下,不太合理
     productList.value = [
       { id: 1, name: '智能温度传感器', productKey: 'temp_sensor_001', status: 0 },
       { id: 2, name: '智能空调控制器', productKey: 'ac_controller_001', status: 0 },
@@ -247,6 +248,7 @@ const getDeviceList = async (productId: number) => {
   } catch (error) {
     console.error('获取设备列表失败:', error)
     // 模拟数据
+    // TODO @puhui999:移除下,不太合理
     deviceList.value = [
       { id: 1, deviceName: 'sensor_001', nickname: '客厅温度传感器', state: 1, productId },
       { id: 2, deviceName: 'sensor_002', nickname: '卧室温度传感器', state: 2, productId },
@@ -261,7 +263,7 @@ const getDeviceList = async (productId: number) => {
 onMounted(async () => {
   await getProductList()
 
-  // 根据初始设备ID设置选择模式
+  // 根据初始设备 ID 设置选择模式
   if (localDeviceId.value === 0) {
     deviceSelectionMode.value = 'all'
   } else if (localDeviceId.value) {
@@ -274,11 +276,15 @@ onMounted(async () => {
 })
 
 // 监听产品变化
-watch(() => localProductId.value, async (newProductId) => {
-  if (newProductId && deviceList.value.length === 0) {
-    await getDeviceList(newProductId)
+watch(
+  () => localProductId.value,
+  async (newProductId) => {
+    if (newProductId && deviceList.value.length === 0) {
+      await getDeviceList(newProductId)
+    }
   }
-})
+)
+// TODO @puhui999:是不是 unocss
 </script>
 
 <style scoped>

+ 40 - 36
src/views/iot/rule/scene/components/selectors/PropertySelector.vue

@@ -1,4 +1,5 @@
 <!-- 属性选择器组件 -->
+<!-- TODO @yunai:可能要在 review 下 -->
 <template>
   <div class="property-selector">
     <el-select
@@ -10,11 +11,7 @@
       class="w-full"
       :loading="loading"
     >
-      <el-option-group
-        v-for="group in propertyGroups"
-        :key="group.label"
-        :label="group.label"
-      >
+      <el-option-group v-for="group in propertyGroups" :key="group.label" :label="group.label">
         <el-option
           v-for="property in group.options"
           :key="property.identifier"
@@ -70,7 +67,7 @@
 <script setup lang="ts">
 import { useVModel } from '@vueuse/core'
 import { IotRuleSceneTriggerTypeEnum } from '@/api/iot/rule/scene/scene.types'
-import { ThingModelApi, ThingModelData } from '@/api/iot/thingmodel'
+import { ThingModelApi } from '@/api/iot/thingmodel'
 import { IoTThingModelTypeEnum } from '@/views/iot/utils/constants'
 import type { IotThingModelTSLRespVO, PropertySelectorItem } from './types'
 
@@ -106,65 +103,65 @@ const propertyGroups = computed(() => {
   if (props.triggerType === IotRuleSceneTriggerTypeEnum.DEVICE_PROPERTY_POST) {
     groups.push({
       label: '设备属性',
-      options: propertyList.value.filter(p => p.type === IoTThingModelTypeEnum.PROPERTY)
+      options: propertyList.value.filter((p) => p.type === IoTThingModelTypeEnum.PROPERTY)
     })
   }
 
   if (props.triggerType === IotRuleSceneTriggerTypeEnum.DEVICE_EVENT_POST) {
     groups.push({
       label: '设备事件',
-      options: propertyList.value.filter(p => p.type === IoTThingModelTypeEnum.EVENT)
+      options: propertyList.value.filter((p) => p.type === IoTThingModelTypeEnum.EVENT)
     })
   }
 
   if (props.triggerType === IotRuleSceneTriggerTypeEnum.DEVICE_SERVICE_INVOKE) {
     groups.push({
       label: '设备服务',
-      options: propertyList.value.filter(p => p.type === IoTThingModelTypeEnum.SERVICE)
+      options: propertyList.value.filter((p) => p.type === IoTThingModelTypeEnum.SERVICE)
     })
   }
 
-  return groups.filter(group => group.options.length > 0)
+  return groups.filter((group) => group.options.length > 0)
 })
 
 const selectedProperty = computed(() => {
-  return propertyList.value.find(p => p.identifier === localValue.value)
+  return propertyList.value.find((p) => p.identifier === localValue.value)
 })
 
 // 工具函数
 const getPropertyTypeName = (dataType: string) => {
   const typeMap = {
-    'int': '整数',
-    'float': '浮点数',
-    'double': '双精度',
-    'text': '字符串',
-    'bool': '布尔值',
-    'enum': '枚举',
-    'date': '日期',
-    'struct': '结构体',
-    'array': '数组'
+    int: '整数',
+    float: '浮点数',
+    double: '双精度',
+    text: '字符串',
+    bool: '布尔值',
+    enum: '枚举',
+    date: '日期',
+    struct: '结构体',
+    array: '数组'
   }
   return typeMap[dataType] || dataType
 }
 
 const getPropertyTypeTag = (dataType: string) => {
   const tagMap = {
-    'int': 'primary',
-    'float': 'success',
-    'double': 'success',
-    'text': 'info',
-    'bool': 'warning',
-    'enum': 'danger',
-    'date': 'primary',
-    'struct': 'info',
-    'array': 'warning'
+    int: 'primary',
+    float: 'success',
+    double: 'success',
+    text: 'info',
+    bool: 'warning',
+    enum: 'danger',
+    date: 'primary',
+    struct: 'info',
+    array: 'warning'
   }
   return tagMap[dataType] || 'info'
 }
 
 // 事件处理
 const handleChange = (value: string) => {
-  const property = propertyList.value.find(p => p.identifier === value)
+  const property = propertyList.value.find((p) => p.identifier === value)
   if (property) {
     emit('change', {
       type: property.dataType,
@@ -321,14 +318,21 @@ const getDataRange = (dataSpecs: any) => {
 }
 
 // 监听产品变化
-watch(() => props.productId, () => {
-  getThingModelTSL()
-}, { immediate: true })
+watch(
+  () => props.productId,
+  () => {
+    getThingModelTSL()
+  },
+  { immediate: true }
+)
 
 // 监听触发类型变化
-watch(() => props.triggerType, () => {
-  localValue.value = ''
-})
+watch(
+  () => props.triggerType,
+  () => {
+    localValue.value = ''
+  }
+)
 </script>
 
 <style scoped>

+ 11 - 31
src/views/iot/rule/scene/components/selectors/TriggerTypeSelector.vue

@@ -16,12 +16,14 @@
         >
           <div class="trigger-option">
             <div class="option-content">
+              <!-- TODO @puhui999:貌似没对齐? -->
               <Icon :icon="option.icon" class="option-icon" />
               <div class="option-info">
                 <div class="option-label">{{ option.label }}</div>
                 <div class="option-desc">{{ option.description }}</div>
               </div>
             </div>
+            <!-- TODO @puhui999:这个要不去掉? -->
             <el-tag :type="option.tag" size="small">
               {{ option.category }}
             </el-tag>
@@ -31,6 +33,7 @@
     </el-form-item>
 
     <!-- 类型说明 -->
+    <!-- TODO @puhui999:这个去掉。感觉没啥内容哈; -->
     <div v-if="selectedOption" class="type-description">
       <div class="desc-header">
         <Icon :icon="selectedOption.icon" class="desc-icon" />
@@ -39,11 +42,7 @@
       <div class="desc-content">
         <p class="desc-text">{{ selectedOption.description }}</p>
         <div class="desc-features">
-          <div
-            v-for="feature in selectedOption.features"
-            :key="feature"
-            class="feature-item"
-          >
+          <div v-for="feature in selectedOption.features" :key="feature" class="feature-item">
             <Icon icon="ep:check" class="feature-icon" />
             <span class="feature-text">{{ feature }}</span>
           </div>
@@ -83,11 +82,7 @@ const triggerTypeOptions = [
     icon: 'ep:connection',
     tag: 'warning',
     category: '设备状态',
-    features: [
-      '监控设备连接状态',
-      '实时响应设备变化',
-      '无需配置额外条件'
-    ]
+    features: ['监控设备连接状态', '实时响应设备变化', '无需配置额外条件']
   },
   {
     value: IotRuleSceneTriggerTypeEnum.DEVICE_PROPERTY_POST,
@@ -96,11 +91,7 @@ const triggerTypeOptions = [
     icon: 'ep:data-line',
     tag: 'primary',
     category: '数据监控',
-    features: [
-      '监控设备属性变化',
-      '支持多种比较条件',
-      '可配置阈值范围'
-    ]
+    features: ['监控设备属性变化', '支持多种比较条件', '可配置阈值范围']
   },
   {
     value: IotRuleSceneTriggerTypeEnum.DEVICE_EVENT_POST,
@@ -109,11 +100,7 @@ const triggerTypeOptions = [
     icon: 'ep:bell',
     tag: 'success',
     category: '事件监控',
-    features: [
-      '监控设备事件',
-      '支持事件参数过滤',
-      '实时事件响应'
-    ]
+    features: ['监控设备事件', '支持事件参数过滤', '实时事件响应']
   },
   {
     value: IotRuleSceneTriggerTypeEnum.DEVICE_SERVICE_INVOKE,
@@ -122,11 +109,7 @@ const triggerTypeOptions = [
     icon: 'ep:service',
     tag: 'info',
     category: '服务监控',
-    features: [
-      '监控服务调用',
-      '支持参数条件',
-      '服务执行跟踪'
-    ]
+    features: ['监控服务调用', '支持参数条件', '服务执行跟踪']
   },
   {
     value: IotRuleSceneTriggerTypeEnum.TIMER,
@@ -135,17 +118,13 @@ const triggerTypeOptions = [
     icon: 'ep:timer',
     tag: 'danger',
     category: '定时任务',
-    features: [
-      '支持CRON表达式',
-      '灵活的时间配置',
-      '可视化时间设置'
-    ]
+    features: ['支持CRON表达式', '灵活的时间配置', '可视化时间设置']
   }
 ]
 
 // 计算属性
 const selectedOption = computed(() => {
-  return triggerTypeOptions.find(option => option.value === localValue.value)
+  return triggerTypeOptions.find((option) => option.value === localValue.value)
 })
 
 // 事件处理
@@ -155,6 +134,7 @@ const handleChange = (value: number) => {
 </script>
 
 <style scoped>
+/** TODO @puhui999:unocss 哈 */
 .trigger-type-selector {
   width: 100%;
 }

+ 13 - 9
src/views/iot/rule/scene/index.vue

@@ -1,4 +1,3 @@
-<!-- 改进的场景联动规则管理页面 -->
 <template>
   <ContentWrap>
     <!-- 页面头部 -->
@@ -186,6 +185,7 @@
         </el-table-column>
         <el-table-column label="操作" width="200" fixed="right">
           <template #default="{ row }">
+            <!-- TODO @puhui999:间隙大了点 -->
             <div class="action-buttons">
               <el-button type="primary" link @click="handleEdit(row)">
                 <Icon icon="ep:edit" />
@@ -197,6 +197,7 @@
                 @click="handleToggleStatus(row)"
               >
                 <Icon :icon="row.status === 0 ? 'ep:video-pause' : 'ep:video-play'" />
+                <!-- TODO @puhui999:翻译,字典 -->
                 {{ row.status === 0 ? '禁用' : '启用' }}
               </el-button>
               <el-button type="danger" link @click="handleDelete(row)">
@@ -241,7 +242,7 @@
     </div>
 
     <!-- 表单对话框 -->
-    <RuleSceneForm v-model="formVisible" :rule-scene="currentRule" @success="handleFormSuccess" />
+    <RuleSceneForm v-model="formVisible" :rule-scene="currentRule" @success="getList" />
   </ContentWrap>
 </template>
 
@@ -252,11 +253,11 @@ import { IotRuleScene } from '@/api/iot/rule/scene/scene.types'
 import { getRuleSceneSummary } from './utils/transform'
 import { formatDate } from '@/utils/formatTime'
 
-/** 改进的场景联动规则管理页面 */
-defineOptions({ name: 'ImprovedRuleSceneIndex' })
+/** 场景联动规则管理页面 */
+defineOptions({ name: 'IoTSceneRule' })
 
 const message = useMessage()
-// const { t } = useI18n()
+// const { t } = useI18n() // TODO @puhui999:可以删除
 
 // 查询参数
 const queryParams = reactive({
@@ -267,6 +268,7 @@ const queryParams = reactive({
 })
 
 // 数据状态
+// TODO @puhui999:变量名,和别的页面保持一致哈
 const loading = ref(true)
 const list = ref<IotRuleScene[]>([])
 const total = ref(0)
@@ -285,6 +287,7 @@ const statistics = ref({
 })
 
 // 获取列表数据
+// TODO @puhui999:接入
 const getList = async () => {
   loading.value = true
   try {
@@ -352,6 +355,8 @@ const getList = async () => {
   }
 }
 
+// TODO @puhui999:方法注释,使用 /** */ 风格
+
 // 更新统计数据
 const updateStatistics = () => {
   statistics.value = {
@@ -384,6 +389,7 @@ const resetQuery = () => {
   handleQuery()
 }
 
+// TODO @puhui999:这个要不还是使用 open 方式,只是弹出的右侧;
 const handleAdd = () => {
   currentRule.value = undefined
   formVisible.value = true
@@ -394,6 +400,7 @@ const handleEdit = (row: IotRuleScene) => {
   formVisible.value = true
 }
 
+// TODO @puhui999:handleDelete、handleToggleStatus 保持和别的模块一致哇?
 const handleDelete = async (row: IotRuleScene) => {
   try {
     await ElMessageBox.confirm('确定要删除这个规则吗?', '提示', {
@@ -481,10 +488,6 @@ const handleBatchDelete = async () => {
   }
 }
 
-const handleFormSuccess = () => {
-  getList()
-}
-
 // 初始化
 onMounted(() => {
   getList()
@@ -492,6 +495,7 @@ onMounted(() => {
 </script>
 
 <style scoped>
+/** TODO @puhui999:看看下面的,是不是可以用 unocss 替代 */
 .page-header {
   display: flex;
   justify-content: space-between;