review:【iot 物联网】场景联动的 review
This commit is contained in:
@ -1,5 +1,5 @@
|
||||
<!-- IoT场景联动规则表单 - 主表单组件 -->
|
||||
<template>
|
||||
<!-- TODO @puhui999:这个抽屉的高度太高了?! -->
|
||||
<el-drawer
|
||||
v-model="drawerVisible"
|
||||
:title="drawerTitle"
|
||||
@ -28,7 +28,6 @@
|
||||
<ActionSection v-model:actions="formData.actions" @validate="handleActionValidate" />
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<el-button :disabled="submitLoading" type="primary" @click="handleSubmit">确 定</el-button>
|
||||
<el-button @click="handleClose">取 消</el-button>
|
||||
@ -55,11 +54,13 @@ import { generateUUID } from '@/utils'
|
||||
/** IoT 场景联动规则表单 - 主表单组件 */
|
||||
defineOptions({ name: 'RuleSceneForm' })
|
||||
|
||||
// TODO @puhui999:是不是融合到 props
|
||||
interface Props {
|
||||
modelValue: boolean
|
||||
ruleScene?: IotRuleScene
|
||||
}
|
||||
|
||||
// TODO @puhui999:Emits 是不是融合到 emit
|
||||
interface Emits {
|
||||
(e: 'update:modelValue', value: boolean): void
|
||||
(e: 'success'): void
|
||||
@ -68,11 +69,11 @@ interface Emits {
|
||||
const props = defineProps<Props>()
|
||||
const emit = defineEmits<Emits>()
|
||||
|
||||
const drawerVisible = useVModel(props, 'modelValue', emit)
|
||||
const drawerVisible = useVModel(props, 'modelValue', emit) // 是否可见
|
||||
|
||||
/**
|
||||
* 创建默认的表单数据
|
||||
*/
|
||||
// TODO @puhui999:使用 /** 注释风格哈 */
|
||||
|
||||
/** 创建默认的表单数据 */
|
||||
const createDefaultFormData = (): RuleSceneFormData => {
|
||||
return {
|
||||
name: '',
|
||||
@ -93,8 +94,9 @@ const createDefaultFormData = (): RuleSceneFormData => {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO @puhui999:使用 convertFormToVO;下面也是类似哈;
|
||||
/**
|
||||
* 将表单数据转换为API请求格式
|
||||
* 将表单数据转换为 API 请求格式
|
||||
*/
|
||||
const transformFormToApi = (formData: RuleSceneFormData): IotRuleScene => {
|
||||
return {
|
||||
@ -196,7 +198,6 @@ const handleSubmit = async () => {
|
||||
if (!formRef.value) return
|
||||
const valid = await formRef.value.validate()
|
||||
if (!valid) return
|
||||
|
||||
// 验证触发器和执行器
|
||||
if (!triggerValidation.value.valid) {
|
||||
ElMessage.error(triggerValidation.value.message)
|
||||
@ -214,6 +215,7 @@ const handleSubmit = async () => {
|
||||
const apiData = transformFormToApi(formData.value)
|
||||
|
||||
// 这里应该调用API保存数据
|
||||
// TODO @puhui999:貌似还没接入
|
||||
console.log('提交数据:', apiData)
|
||||
|
||||
// 模拟API调用
|
||||
@ -250,7 +252,7 @@ watch(drawerVisible, (visible) => {
|
||||
}
|
||||
})
|
||||
|
||||
// 监听props变化
|
||||
// 监听 props 变化
|
||||
watch(
|
||||
() => props.ruleScene,
|
||||
() => {
|
||||
@ -261,6 +263,7 @@ watch(
|
||||
)
|
||||
</script>
|
||||
|
||||
<!-- TODO @puhui999:看看下面样式,哪些是必要添加的 -->
|
||||
<style scoped>
|
||||
/* 滚动条样式 */
|
||||
.h-\[calc\(100vh-120px\)\]::-webkit-scrollbar {
|
||||
|
||||
@ -91,6 +91,7 @@
|
||||
</el-row>
|
||||
|
||||
<!-- 条件预览 -->
|
||||
<!-- TODO puhui999:可以去掉。。。因为表单选择了,可以看懂的呀。 -->
|
||||
<div
|
||||
v-if="conditionPreview"
|
||||
class="p-12px bg-[var(--el-fill-color-light)] rounded-6px border border-[var(--el-border-color-lighter)]"
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<!-- 条件组容器配置组件 -->
|
||||
<template>
|
||||
<div class="flex flex-col gap-16px">
|
||||
<!-- 条件组容器头部 -->
|
||||
<!-- TODO @puhui999:这个是不是删除,不然有两个“附件条件组”的 header -->
|
||||
<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"
|
||||
>
|
||||
@ -39,6 +39,7 @@
|
||||
<!-- 子条件组列表 -->
|
||||
<div v-if="modelValue.subGroups && modelValue.subGroups.length > 0" class="space-y-16px">
|
||||
<!-- 逻辑关系说明 -->
|
||||
<!-- TODO @puhui999:这个可以去掉。。。提示有点太多了。 -->
|
||||
<div v-if="modelValue.subGroups.length > 1" class="flex items-center justify-center">
|
||||
<div
|
||||
class="flex items-center gap-8px px-12px py-6px bg-orange-50 border border-orange-200 rounded-full text-12px text-orange-600"
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
<!-- 当前时间条件配置组件 -->
|
||||
<template>
|
||||
<div class="flex flex-col gap-16px">
|
||||
<div class="flex items-center gap-8px p-12px px-16px bg-orange-50 rounded-6px border border-orange-200">
|
||||
<div
|
||||
class="flex items-center gap-8px p-12px px-16px bg-orange-50 rounded-6px border border-orange-200"
|
||||
>
|
||||
<Icon icon="ep:timer" class="text-orange-500 text-18px" />
|
||||
<span class="text-14px font-500 text-orange-700">当前时间条件配置</span>
|
||||
</div>
|
||||
@ -89,13 +91,20 @@
|
||||
</el-row>
|
||||
|
||||
<!-- 条件预览 -->
|
||||
<div v-if="conditionPreview" class="p-12px bg-[var(--el-fill-color-light)] rounded-6px border border-[var(--el-border-color-lighter)]">
|
||||
<!-- puhui999:可以去掉。。。因为表单选择了,可以看懂的呀。 -->
|
||||
<div
|
||||
v-if="conditionPreview"
|
||||
class="p-12px bg-[var(--el-fill-color-light)] rounded-6px border border-[var(--el-border-color-lighter)]"
|
||||
>
|
||||
<div class="flex items-center gap-8px mb-8px">
|
||||
<Icon icon="ep:view" class="text-[var(--el-color-info)] text-16px" />
|
||||
<span class="text-14px font-500 text-[var(--el-text-color-primary)]">条件预览</span>
|
||||
</div>
|
||||
<div class="pl-24px">
|
||||
<code class="text-12px text-[var(--el-color-primary)] bg-[var(--el-fill-color-blank)] p-8px rounded-4px font-mono">{{ conditionPreview }}</code>
|
||||
<code
|
||||
class="text-12px text-[var(--el-color-primary)] bg-[var(--el-fill-color-blank)] p-8px rounded-4px font-mono"
|
||||
>{{ conditionPreview }}</code
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -113,7 +122,10 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useVModel } from '@vueuse/core'
|
||||
import { ConditionFormData, IotRuleSceneTriggerTimeOperatorEnum } from '@/api/iot/rule/scene/scene.types'
|
||||
import {
|
||||
ConditionFormData,
|
||||
IotRuleSceneTriggerTimeOperatorEnum
|
||||
} from '@/api/iot/rule/scene/scene.types'
|
||||
|
||||
/** 当前时间条件配置组件 */
|
||||
defineOptions({ name: 'CurrentTimeConditionConfig' })
|
||||
@ -203,22 +215,22 @@ const conditionPreview = computed(() => {
|
||||
if (!condition.value.operator) {
|
||||
return ''
|
||||
}
|
||||
|
||||
const operatorOption = timeOperatorOptions.find(opt => opt.value === condition.value.operator)
|
||||
|
||||
const operatorOption = timeOperatorOptions.find((opt) => opt.value === condition.value.operator)
|
||||
const operatorLabel = operatorOption?.label || condition.value.operator
|
||||
|
||||
|
||||
if (condition.value.operator === IotRuleSceneTriggerTimeOperatorEnum.TODAY.value) {
|
||||
return `当前时间 ${operatorLabel}`
|
||||
}
|
||||
|
||||
|
||||
if (!condition.value.timeValue) {
|
||||
return `当前时间 ${operatorLabel} [未设置时间]`
|
||||
}
|
||||
|
||||
|
||||
if (needsSecondTimeInput.value && condition.value.timeValue2) {
|
||||
return `当前时间 ${operatorLabel} ${condition.value.timeValue} 和 ${condition.value.timeValue2}`
|
||||
}
|
||||
|
||||
|
||||
return `当前时间 ${operatorLabel} ${condition.value.timeValue}`
|
||||
})
|
||||
|
||||
|
||||
@ -79,6 +79,7 @@
|
||||
</el-row>
|
||||
|
||||
<!-- 条件预览 -->
|
||||
<!-- TODO puhui999:可以去掉。。。因为表单选择了,可以看懂的呀。 -->
|
||||
<div
|
||||
v-if="conditionPreview"
|
||||
class="p-12px bg-[var(--el-fill-color-light)] rounded-6px border border-[var(--el-border-color-lighter)]"
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
<span class="text-14px font-500 text-[var(--el-text-color-primary)]">附加条件组</span>
|
||||
<el-tag size="small" type="success">与主条件为且关系</el-tag>
|
||||
<el-tag size="small" type="info">
|
||||
{{ trigger.conditionGroup?.subGroups?.length || 0 }}个子条件组
|
||||
{{ trigger.conditionGroup?.subGroups?.length || 0 }} 个子条件组
|
||||
</el-tag>
|
||||
</div>
|
||||
<el-button
|
||||
@ -70,6 +70,7 @@ import {
|
||||
/** 设备触发配置组件 */
|
||||
defineOptions({ name: 'DeviceTriggerConfig' })
|
||||
|
||||
// TODO @puhui999:下面的 Props、Emits 可以合并到变量那;
|
||||
interface Props {
|
||||
modelValue: TriggerFormData
|
||||
}
|
||||
@ -92,8 +93,6 @@ const mainConditionValidation = ref<{ valid: boolean; message: string }>({
|
||||
const validationMessage = ref('')
|
||||
const isValid = ref(true)
|
||||
|
||||
// 计算属性
|
||||
|
||||
// 初始化主条件
|
||||
const initMainCondition = () => {
|
||||
if (!trigger.value.mainCondition) {
|
||||
|
||||
@ -20,6 +20,7 @@
|
||||
</div>
|
||||
|
||||
<!-- 主条件配置 -->
|
||||
<!-- TODO @puhui999:这里可以简化下,主条件是不能删除的。。。 -->
|
||||
<div v-else class="space-y-16px">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-8px">
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
<!-- 主条件内部配置组件 - 不显示条件类型选择 -->
|
||||
<template>
|
||||
<div class="space-y-16px">
|
||||
<!-- 触发事件类型显示 -->
|
||||
@ -76,6 +75,7 @@
|
||||
</el-row>
|
||||
|
||||
<!-- 条件预览 -->
|
||||
<!-- TODO puhui999:可以去掉。。。因为表单选择了,可以看懂的呀。 -->
|
||||
<div v-if="conditionPreview" class="mt-12px">
|
||||
<div class="text-12px text-[var(--el-text-color-secondary)]">
|
||||
预览:{{ conditionPreview }}
|
||||
@ -133,6 +133,7 @@ const emit = defineEmits<Emits>()
|
||||
|
||||
// 响应式数据
|
||||
const condition = useVModel(props, 'modelValue', emit)
|
||||
// TODO @puhui999:是不是 validationMessage 非空,就是不通过哈;
|
||||
const isValid = ref(true)
|
||||
const validationMessage = ref('')
|
||||
const propertyType = ref('')
|
||||
@ -159,6 +160,7 @@ const conditionPreview = computed(() => {
|
||||
})
|
||||
|
||||
// 获取触发类型文本
|
||||
// TODO @puhui999:是不是有枚举可以服用哈;
|
||||
const getTriggerTypeText = (type: number) => {
|
||||
switch (type) {
|
||||
case IotRuleSceneTriggerTypeEnum.DEVICE_PROPERTY_POST:
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
<!-- 子条件组配置组件 -->
|
||||
<template>
|
||||
<div class="p-16px">
|
||||
<!-- 空状态 -->
|
||||
@ -66,6 +65,7 @@
|
||||
</div>
|
||||
|
||||
<!-- 条件间的"且"连接符 -->
|
||||
<!-- TODO @puhu999:建议去掉,有点元素太丰富了。 -->
|
||||
<div
|
||||
v-if="conditionIndex < subGroup.conditions!.length - 1"
|
||||
class="flex items-center justify-center py-8px"
|
||||
|
||||
@ -1,13 +1,16 @@
|
||||
<!-- 定时触发配置组件 -->
|
||||
<template>
|
||||
<div class="flex flex-col gap-16px">
|
||||
<div class="flex items-center gap-8px p-12px px-16px bg-[var(--el-fill-color-light)] rounded-6px border border-[var(--el-border-color-lighter)]">
|
||||
<div
|
||||
class="flex items-center gap-8px p-12px px-16px bg-[var(--el-fill-color-light)] rounded-6px border border-[var(--el-border-color-lighter)]"
|
||||
>
|
||||
<Icon icon="ep:timer" class="text-[var(--el-color-danger)] text-18px" />
|
||||
<span class="text-14px font-500 text-[var(--el-text-color-primary)]">定时触发配置</span>
|
||||
</div>
|
||||
|
||||
<!-- CRON表达式配置 -->
|
||||
<div class="p-16px border border-[var(--el-border-color-lighter)] rounded-6px bg-[var(--el-fill-color-blank)]">
|
||||
<!-- CRON 表达式配置 -->
|
||||
<div
|
||||
class="p-16px border border-[var(--el-border-color-lighter)] rounded-6px bg-[var(--el-fill-color-blank)]"
|
||||
>
|
||||
<el-form-item label="CRON表达式" required>
|
||||
<Crontab v-model="localValue" />
|
||||
</el-form-item>
|
||||
@ -22,6 +25,7 @@ import { Crontab } from '@/components/Crontab'
|
||||
/** 定时触发配置组件 */
|
||||
defineOptions({ name: 'TimerTriggerConfig' })
|
||||
|
||||
// TODO @puhui999:下面的 Props、Emits 可以合并到变量那;
|
||||
interface Props {
|
||||
modelValue?: string
|
||||
}
|
||||
@ -37,4 +41,4 @@ const emit = defineEmits<Emits>()
|
||||
const localValue = useVModel(props, 'modelValue', emit, {
|
||||
defaultValue: '0 0 12 * * ?'
|
||||
})
|
||||
</script>
|
||||
</script>
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
<span class="text-16px font-600 text-[var(--el-text-color-primary)]">基础信息</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-8px">
|
||||
<!-- TODO @puhui999:dict-tag 可以哇? -->
|
||||
<el-tag :type="formData.status === 0 ? 'success' : 'danger'" size="small">
|
||||
{{ formData.status === 0 ? '启用' : '禁用' }}
|
||||
</el-tag>
|
||||
@ -65,6 +66,8 @@ import { RuleSceneFormData } from '@/api/iot/rule/scene/scene.types'
|
||||
/** 基础信息配置组件 */
|
||||
defineOptions({ name: 'BasicInfoSection' })
|
||||
|
||||
// TODO @puhui999:下面的 Props、Emits 可以合并到变量那;
|
||||
|
||||
interface Props {
|
||||
modelValue: RuleSceneFormData
|
||||
rules?: any
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<!-- 场景触发器配置组件 -->
|
||||
<template>
|
||||
<el-card class="border border-[var(--el-border-color-light)] rounded-8px" shadow="never">
|
||||
<!-- TODO @puhui999:触发器还是多个。。。每个触发器里面有事件类型 + 附加条件组(最好文案上,和阿里 iot 保持相对一致) -->
|
||||
<template #header>
|
||||
<div class="flex items-center gap-8px">
|
||||
<Icon icon="ep:lightning" class="text-[var(--el-color-primary)] text-18px" />
|
||||
@ -36,6 +36,7 @@
|
||||
/>
|
||||
|
||||
<!-- 定时触发配置 -->
|
||||
<!-- TODO @puhui999:这里要不 v-else 好了? -->
|
||||
<TimerTriggerConfig
|
||||
v-if="trigger.type === TriggerTypeEnum.TIMER"
|
||||
:model-value="trigger.cronExpression"
|
||||
@ -57,6 +58,7 @@ import {
|
||||
/** 触发器配置组件 */
|
||||
defineOptions({ name: 'TriggerSection' })
|
||||
|
||||
// TODO @puhui999:下面的 Props、Emits 可以合并到变量那;
|
||||
interface Props {
|
||||
trigger: TriggerFormData
|
||||
}
|
||||
@ -71,6 +73,7 @@ const emit = defineEmits<Emits>()
|
||||
const trigger = useVModel(props, 'trigger', emit)
|
||||
|
||||
// 触发器类型选项
|
||||
// TODO @puhui999:/Users/yunai/Java/yudao-ui-admin-vue3/src/views/iot/utils/constants.ts
|
||||
const triggerTypeOptions = [
|
||||
{
|
||||
value: TriggerTypeEnum.DEVICE_STATE_UPDATE,
|
||||
@ -95,6 +98,7 @@ const triggerTypeOptions = [
|
||||
]
|
||||
|
||||
// 工具函数
|
||||
// TODO @puhui999:/Users/yunai/Java/yudao-ui-admin-vue3/src/views/iot/utils/constants.ts
|
||||
const isDeviceTrigger = (type: number) => {
|
||||
const deviceTriggerTypes = [
|
||||
TriggerTypeEnum.DEVICE_STATE_UPDATE,
|
||||
@ -111,10 +115,12 @@ const updateTriggerType = (type: number) => {
|
||||
onTriggerTypeChange(type)
|
||||
}
|
||||
|
||||
// TODO @puhui999:updateTriggerDeviceConfig
|
||||
const updateTrigger = (newTrigger: TriggerFormData) => {
|
||||
trigger.value = newTrigger
|
||||
}
|
||||
|
||||
// TODO @puhui999:updateTriggerCronConfig
|
||||
const updateTriggerCronExpression = (cronExpression?: string) => {
|
||||
trigger.value.cronExpression = cronExpression
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user