perf:【IoT 物联网】场景联动优化统一类型定义,简化告警配置
parent
694de3f0d1
commit
6c954c4ff1
|
|
@ -1,5 +1,5 @@
|
|||
import request from '@/config/axios'
|
||||
import { IotRuleScene } from './scene.types'
|
||||
import { IotSceneRule } from './scene.types'
|
||||
|
||||
// IoT 场景联动 API
|
||||
export const RuleSceneApi = {
|
||||
|
|
@ -14,21 +14,24 @@ export const RuleSceneApi = {
|
|||
},
|
||||
|
||||
// 新增场景联动
|
||||
createRuleScene: async (data: IotRuleScene) => {
|
||||
createRuleScene: async (data: IotSceneRule) => {
|
||||
return await request.post({ url: `/iot/rule-scene/create`, data })
|
||||
},
|
||||
|
||||
// 修改场景联动
|
||||
updateRuleScene: async (data: IotRuleScene) => {
|
||||
updateRuleScene: async (data: IotSceneRule) => {
|
||||
return await request.put({ url: `/iot/rule-scene/update`, data })
|
||||
},
|
||||
|
||||
// 修改场景联动
|
||||
updateRuleSceneStatus: async (id: number, status: number) => {
|
||||
return await request.put({ url: `/iot/rule-scene/update-status`, data: {
|
||||
return await request.put({
|
||||
url: `/iot/rule-scene/update-status`,
|
||||
data: {
|
||||
id,
|
||||
status
|
||||
}})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 删除场景联动
|
||||
|
|
|
|||
|
|
@ -137,122 +137,18 @@ export interface PropertySelectorItem {
|
|||
|
||||
// ========== 场景联动规则相关接口定义 ==========
|
||||
|
||||
// 基础接口(如果项目中有全局的 BaseDO,可以使用全局的)
|
||||
interface TenantBaseDO {
|
||||
createTime?: Date // 创建时间
|
||||
updateTime?: Date // 更新时间
|
||||
creator?: string // 创建者
|
||||
updater?: string // 更新者
|
||||
deleted?: boolean // 是否删除
|
||||
tenantId?: number // 租户编号
|
||||
}
|
||||
|
||||
// 触发条件参数
|
||||
interface TriggerConditionParameter {
|
||||
identifier0?: string // 标识符(事件、服务)
|
||||
identifier?: string // 标识符(属性)
|
||||
operator: string // 操作符(必填)
|
||||
value: string // 比较值(必填,多值用逗号分隔)
|
||||
}
|
||||
|
||||
// 触发条件
|
||||
interface TriggerCondition {
|
||||
type: string // 消息类型
|
||||
identifier: string // 消息标识符
|
||||
parameters: TriggerConditionParameter[] // 参数数组
|
||||
}
|
||||
|
||||
// 触发器配置
|
||||
interface TriggerConfig {
|
||||
key?: string // 组件唯一标识符,用于解决索引重用问题
|
||||
type: number // 触发类型(必填)
|
||||
productKey?: string // 产品标识(设备触发时必填)
|
||||
deviceNames?: string[] // 设备名称数组(设备触发时必填)
|
||||
conditions?: TriggerCondition[] // 触发条件数组(设备触发时必填)
|
||||
cronExpression?: string // CRON表达式(定时触发时必填)
|
||||
}
|
||||
|
||||
// 执行设备控制
|
||||
interface ActionDeviceControl {
|
||||
productKey: string // 产品标识(必填)
|
||||
deviceNames: string[] // 设备名称数组(必填)
|
||||
type: string // 消息类型(必填)
|
||||
identifier: string // 消息标识符(必填)
|
||||
params: Record<string, any> // 参数对象(必填)- 统一使用 params 字段
|
||||
}
|
||||
|
||||
// 执行器配置
|
||||
interface ActionConfig {
|
||||
key?: string // 组件唯一标识符,用于解决索引重用问题
|
||||
type: number // 执行类型(必填)
|
||||
deviceControl?: ActionDeviceControl // 设备控制(设备控制时必填)
|
||||
alertConfigId?: number // 告警配置ID(告警恢复时必填)
|
||||
}
|
||||
|
||||
// 表单数据接口 - 直接对应后端 DO 结构
|
||||
interface RuleSceneFormData {
|
||||
id?: number
|
||||
name: string
|
||||
description?: string
|
||||
status: number
|
||||
triggers: TriggerFormData[] // 支持多个触发器
|
||||
actions: ActionFormData[]
|
||||
}
|
||||
|
||||
// 触发器表单数据 - 直接对应 TriggerDO
|
||||
interface TriggerFormData {
|
||||
type: number // 触发类型
|
||||
productId?: number // 产品编号
|
||||
deviceId?: number // 设备编号
|
||||
identifier?: string // 物模型标识符
|
||||
operator?: string // 操作符
|
||||
value?: string // 参数值
|
||||
cronExpression?: string // CRON 表达式
|
||||
conditionGroups?: TriggerConditionFormData[][] // 条件组(二维数组)
|
||||
}
|
||||
|
||||
// 触发条件表单数据 - 直接对应 TriggerConditionDO
|
||||
interface TriggerConditionFormData {
|
||||
type: number // 条件类型:1-设备状态,2-设备属性,3-当前时间
|
||||
productId?: number // 产品编号
|
||||
deviceId?: number // 设备编号
|
||||
identifier?: string // 标识符
|
||||
operator: string // 操作符
|
||||
param: string // 参数值
|
||||
}
|
||||
|
||||
// 执行器表单数据 - 直接对应 ActionDO
|
||||
interface ActionFormData {
|
||||
type: number // 执行类型
|
||||
productId?: number // 产品编号
|
||||
deviceId?: number // 设备编号
|
||||
identifier?: string // 物模型标识符(服务调用时使用)
|
||||
params?: Record<string, any> // 请求参数
|
||||
alertConfigId?: number // 告警配置编号
|
||||
}
|
||||
|
||||
// 主接口 - 原有的 API 接口格式(保持兼容性)
|
||||
interface IotRuleScene extends TenantBaseDO {
|
||||
id?: number // 场景编号(新增时为空)
|
||||
name: string // 场景名称(必填)
|
||||
description?: string // 场景描述(可选)
|
||||
status: number // 场景状态:0-开启,1-关闭
|
||||
triggers: TriggerConfig[] // 触发器数组(必填,至少一个)
|
||||
actions: ActionConfig[] // 执行器数组(必填,至少一个)
|
||||
}
|
||||
|
||||
// 后端 DO 接口 - 匹配后端数据结构
|
||||
interface IotRuleSceneDO {
|
||||
interface IotSceneRule {
|
||||
id?: number // 场景编号
|
||||
name: string // 场景名称
|
||||
description?: string // 场景描述
|
||||
status: number // 场景状态:0-开启,1-关闭
|
||||
triggers: TriggerDO[] // 触发器数组
|
||||
actions: ActionDO[] // 执行器数组
|
||||
triggers: Trigger[] // 触发器数组
|
||||
actions: Action[] // 执行器数组
|
||||
}
|
||||
|
||||
// 触发器 DO 结构
|
||||
interface TriggerDO {
|
||||
interface Trigger {
|
||||
type: number // 触发类型
|
||||
productId?: number // 产品编号
|
||||
deviceId?: number // 设备编号
|
||||
|
|
@ -260,12 +156,12 @@ interface TriggerDO {
|
|||
operator?: string // 操作符
|
||||
value?: string // 参数值
|
||||
cronExpression?: string // CRON 表达式
|
||||
conditionGroups?: TriggerConditionDO[][] // 条件组(二维数组)
|
||||
conditionGroups?: TriggerCondition[][] // 条件组(二维数组)
|
||||
}
|
||||
|
||||
// 触发条件 DO 结构
|
||||
interface TriggerConditionDO {
|
||||
type: number // 条件类型
|
||||
interface TriggerCondition {
|
||||
type: number // 条件类型:1-设备状态,2-设备属性,3-当前时间
|
||||
productId?: number // 产品编号
|
||||
deviceId?: number // 设备编号
|
||||
identifier?: string // 标识符
|
||||
|
|
@ -274,7 +170,7 @@ interface TriggerConditionDO {
|
|||
}
|
||||
|
||||
// 执行器 DO 结构
|
||||
interface ActionDO {
|
||||
interface Action {
|
||||
type: number // 执行类型
|
||||
productId?: number // 产品编号
|
||||
deviceId?: number // 设备编号
|
||||
|
|
@ -300,21 +196,4 @@ interface FormValidationRules {
|
|||
|
||||
// TODO @puhui999:这个文件,目标最终没有哈,和别的模块一致;
|
||||
|
||||
export {
|
||||
IotRuleScene,
|
||||
IotRuleSceneDO,
|
||||
TriggerDO,
|
||||
TriggerConditionDO,
|
||||
ActionDO,
|
||||
TriggerConfig,
|
||||
TriggerCondition,
|
||||
TriggerConditionParameter,
|
||||
ActionConfig,
|
||||
ActionDeviceControl,
|
||||
RuleSceneFormData,
|
||||
TriggerFormData,
|
||||
TriggerConditionFormData,
|
||||
ActionFormData,
|
||||
ValidationRule,
|
||||
FormValidationRules
|
||||
}
|
||||
export { IotSceneRule, Trigger, TriggerCondition, Action, ValidationRule, FormValidationRules }
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ import { useVModel } from '@vueuse/core'
|
|||
import BasicInfoSection from './sections/BasicInfoSection.vue'
|
||||
import TriggerSection from './sections/TriggerSection.vue'
|
||||
import ActionSection from './sections/ActionSection.vue'
|
||||
import { IotRuleSceneDO, RuleSceneFormData } from '@/api/iot/rule/scene/scene.types'
|
||||
import { IotSceneRule } from '@/api/iot/rule/scene/scene.types'
|
||||
import { RuleSceneApi } from '@/api/iot/rule/scene'
|
||||
import {
|
||||
IotRuleSceneTriggerTypeEnum,
|
||||
|
|
@ -54,7 +54,7 @@ const props = defineProps<{
|
|||
/** 抽屉显示状态 */
|
||||
modelValue: boolean
|
||||
/** 编辑的场景联动规则数据 */
|
||||
ruleScene?: IotRuleSceneDO
|
||||
ruleScene?: IotSceneRule
|
||||
}>()
|
||||
|
||||
/** 组件事件定义 */
|
||||
|
|
@ -66,7 +66,7 @@ const emit = defineEmits<{
|
|||
const drawerVisible = useVModel(props, 'modelValue', emit) // 是否可见
|
||||
|
||||
/** 创建默认的表单数据 */
|
||||
const createDefaultFormData = (): RuleSceneFormData => {
|
||||
const createDefaultFormData = (): IotSceneRule => {
|
||||
return {
|
||||
name: '',
|
||||
description: '',
|
||||
|
|
@ -89,7 +89,7 @@ const createDefaultFormData = (): RuleSceneFormData => {
|
|||
|
||||
// 表单数据和状态
|
||||
const formRef = ref()
|
||||
const formData = ref<RuleSceneFormData>(createDefaultFormData())
|
||||
const formData = ref<IotSceneRule>(createDefaultFormData())
|
||||
// 自定义校验器
|
||||
const validateTriggers = (_rule: any, value: any, callback: any) => {
|
||||
if (!value || !Array.isArray(value) || value.length === 0) {
|
||||
|
|
|
|||
|
|
@ -1,16 +1,6 @@
|
|||
<!-- 告警配置组件 -->
|
||||
<template>
|
||||
<div class="w-full">
|
||||
<!-- 告警配置选择区域 -->
|
||||
<div
|
||||
class="border border-[var(--el-border-color-light)] rounded-6px p-16px bg-[var(--el-fill-color-blank)]"
|
||||
>
|
||||
<div class="flex items-center gap-8px mb-12px">
|
||||
<Icon icon="ep:bell" class="text-[var(--el-color-warning)] text-16px" />
|
||||
<span class="text-14px font-600 text-[var(--el-text-color-primary)]">告警配置选择</span>
|
||||
<el-tag size="small" type="warning">必选</el-tag>
|
||||
</div>
|
||||
|
||||
<el-form-item label="告警配置" required>
|
||||
<el-select
|
||||
v-model="localValue"
|
||||
|
|
@ -21,242 +11,71 @@
|
|||
class="w-full"
|
||||
:loading="loading"
|
||||
>
|
||||
<template #empty>
|
||||
<div class="text-center py-20px">
|
||||
<Icon
|
||||
icon="ep:warning"
|
||||
class="text-24px text-[var(--el-text-color-placeholder)] mb-8px"
|
||||
/>
|
||||
<p class="text-12px text-[var(--el-text-color-secondary)]">暂无可用的告警配置</p>
|
||||
</div>
|
||||
</template>
|
||||
<el-option
|
||||
v-for="config in alertConfigs"
|
||||
:key="config.id"
|
||||
:label="config.name"
|
||||
:value="config.id"
|
||||
:disabled="!config.enabled"
|
||||
>
|
||||
<div class="flex items-center justify-between w-full py-6px">
|
||||
<div class="flex items-center gap-12px flex-1">
|
||||
<Icon
|
||||
:icon="config.enabled ? 'ep:circle-check' : 'ep:circle-close'"
|
||||
:class="
|
||||
config.enabled
|
||||
? 'text-[var(--el-color-success)]'
|
||||
: 'text-[var(--el-color-danger)]'
|
||||
"
|
||||
class="text-16px flex-shrink-0"
|
||||
/>
|
||||
<div class="flex-1">
|
||||
<div class="text-14px font-500 text-[var(--el-text-color-primary)] mb-2px">{{
|
||||
config.name
|
||||
}}</div>
|
||||
<div class="text-12px text-[var(--el-text-color-secondary)] line-clamp-1">{{
|
||||
config.description
|
||||
}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-8px">
|
||||
<el-tag :type="getNotifyTypeTag(config.notifyType)" size="small">
|
||||
{{ getNotifyTypeName(config.notifyType) }}
|
||||
</el-tag>
|
||||
<div class="flex items-center justify-between">
|
||||
<span>{{ config.name }}</span>
|
||||
<el-tag :type="config.enabled ? 'success' : 'danger'" size="small">
|
||||
{{ config.enabled ? '启用' : '禁用' }}
|
||||
</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
||||
<!-- 告警配置详情 -->
|
||||
<div
|
||||
v-if="selectedConfig"
|
||||
class="mt-16px border border-[var(--el-border-color-light)] rounded-6px p-16px bg-gradient-to-r from-orange-50 to-yellow-50"
|
||||
>
|
||||
<div class="flex items-center gap-8px mb-16px">
|
||||
<Icon icon="ep:info-filled" class="text-[var(--el-color-warning)] text-18px" />
|
||||
<span class="text-16px font-600 text-[var(--el-text-color-primary)]">配置详情</span>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-16px">
|
||||
<!-- 基本信息 -->
|
||||
<div class="space-y-12px">
|
||||
<div class="flex items-center gap-8px">
|
||||
<Icon icon="ep:document" class="text-[var(--el-color-primary)] text-14px" />
|
||||
<span class="text-14px font-500 text-[var(--el-text-color-primary)]">基本信息</span>
|
||||
</div>
|
||||
<div class="pl-22px space-y-8px">
|
||||
<div class="flex items-start gap-8px">
|
||||
<span class="text-12px text-[var(--el-text-color-secondary)] min-w-60px">名称:</span>
|
||||
<span class="text-12px text-[var(--el-text-color-primary)] flex-1 font-500">{{
|
||||
selectedConfig.name
|
||||
}}</span>
|
||||
</div>
|
||||
<div class="flex items-start gap-8px">
|
||||
<span class="text-12px text-[var(--el-text-color-secondary)] min-w-60px">描述:</span>
|
||||
<span class="text-12px text-[var(--el-text-color-primary)] flex-1">{{
|
||||
selectedConfig.description
|
||||
}}</span>
|
||||
</div>
|
||||
<div class="flex items-start gap-8px">
|
||||
<span class="text-12px text-[var(--el-text-color-secondary)] min-w-60px">状态:</span>
|
||||
<el-tag :type="selectedConfig.enabled ? 'success' : 'danger'" size="small">
|
||||
{{ selectedConfig.enabled ? '启用' : '禁用' }}
|
||||
</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 通知配置 -->
|
||||
<div class="space-y-12px">
|
||||
<div class="flex items-center gap-8px">
|
||||
<Icon icon="ep:message" class="text-[var(--el-color-success)] text-14px" />
|
||||
<span class="text-14px font-500 text-[var(--el-text-color-primary)]">通知配置</span>
|
||||
</div>
|
||||
<div class="pl-22px space-y-8px">
|
||||
<div class="flex items-start gap-8px">
|
||||
<span class="text-12px text-[var(--el-text-color-secondary)] min-w-60px">方式:</span>
|
||||
<el-tag :type="getNotifyTypeTag(selectedConfig.notifyType)" size="small">
|
||||
{{ getNotifyTypeName(selectedConfig.notifyType) }}
|
||||
</el-tag>
|
||||
</div>
|
||||
<div
|
||||
v-if="selectedConfig.receivers && selectedConfig.receivers.length > 0"
|
||||
class="flex items-start gap-8px"
|
||||
>
|
||||
<span class="text-12px text-[var(--el-text-color-secondary)] min-w-60px"
|
||||
>接收人:</span
|
||||
>
|
||||
<div class="flex-1">
|
||||
<div class="flex flex-wrap gap-4px">
|
||||
<el-tag
|
||||
v-for="receiver in selectedConfig.receivers.slice(0, 3)"
|
||||
:key="receiver"
|
||||
size="small"
|
||||
type="info"
|
||||
>
|
||||
{{ receiver }}
|
||||
</el-tag>
|
||||
<el-tag v-if="selectedConfig.receivers.length > 3" size="small" type="info">
|
||||
+{{ selectedConfig.receivers.length - 3 }}
|
||||
</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useVModel } from '@vueuse/core'
|
||||
import { AlertConfigApi } from '@/api/iot/alert/config'
|
||||
|
||||
/** 告警配置组件 */
|
||||
defineOptions({ name: 'AlertConfig' })
|
||||
|
||||
interface Props {
|
||||
const props = defineProps<{
|
||||
modelValue?: number
|
||||
}
|
||||
}>()
|
||||
|
||||
interface Emits {
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:modelValue', value?: number): void
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
const emit = defineEmits<Emits>()
|
||||
}>()
|
||||
|
||||
const localValue = useVModel(props, 'modelValue', emit)
|
||||
|
||||
// 状态
|
||||
const loading = ref(false)
|
||||
const alertConfigs = ref<any[]>([])
|
||||
const loading = ref(false) // 加载状态
|
||||
const alertConfigs = ref<any[]>([]) // 告警配置列表
|
||||
|
||||
// 计算属性
|
||||
const selectedConfig = computed(() => {
|
||||
return alertConfigs.value.find((config) => config.id === localValue.value)
|
||||
})
|
||||
|
||||
// 工具函数
|
||||
const getNotifyTypeName = (type: number) => {
|
||||
const typeMap = {
|
||||
1: '邮件通知',
|
||||
2: '短信通知',
|
||||
3: '微信通知',
|
||||
4: '钉钉通知'
|
||||
}
|
||||
return typeMap[type] || '未知'
|
||||
}
|
||||
|
||||
const getNotifyTypeTag = (type: number) => {
|
||||
const tagMap = {
|
||||
1: 'primary', // 邮件
|
||||
2: 'success', // 短信
|
||||
3: 'warning', // 微信
|
||||
4: 'info' // 钉钉
|
||||
}
|
||||
return tagMap[type] || 'info'
|
||||
}
|
||||
|
||||
// 事件处理
|
||||
/**
|
||||
* 处理选择变化事件
|
||||
* @param value 选中的值
|
||||
*/
|
||||
const handleChange = (value?: number) => {
|
||||
// 可以在这里添加额外的处理逻辑
|
||||
console.log('告警配置选择变化:', value)
|
||||
emit('update:modelValue', value)
|
||||
}
|
||||
|
||||
// API 调用
|
||||
const getAlertConfigs = async () => {
|
||||
/**
|
||||
* 加载告警配置列表
|
||||
*/
|
||||
const loadAlertConfigs = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
// 这里应该调用真实的API获取告警配置
|
||||
// 暂时使用模拟数据
|
||||
// TODO @puhui999:这里是模拟数据
|
||||
alertConfigs.value = [
|
||||
{
|
||||
id: 1,
|
||||
name: '设备异常告警',
|
||||
description: '设备状态异常时发送告警',
|
||||
enabled: true,
|
||||
notifyType: 1,
|
||||
receivers: ['admin@example.com', 'operator@example.com']
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: '温度超限告警',
|
||||
description: '温度超过阈值时发送告警',
|
||||
enabled: true,
|
||||
notifyType: 2,
|
||||
receivers: ['13800138000', '13900139000']
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: '系统故障告警',
|
||||
description: '系统发生故障时发送告警',
|
||||
enabled: false,
|
||||
notifyType: 3,
|
||||
receivers: ['技术支持群']
|
||||
}
|
||||
]
|
||||
} catch (error) {
|
||||
console.error('获取告警配置失败:', error)
|
||||
const data = await AlertConfigApi.getAlertConfigPage({
|
||||
pageNo: 1,
|
||||
pageSize: 100,
|
||||
enabled: true // 只加载启用的配置
|
||||
})
|
||||
alertConfigs.value = data.list || []
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化
|
||||
// 组件挂载时加载数据
|
||||
onMounted(() => {
|
||||
getAlertConfigs()
|
||||
loadAlertConfigs()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
:deep(.el-select-dropdown__item) {
|
||||
height: auto;
|
||||
padding: 8px 20px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ import DeviceSelector from '../selectors/DeviceSelector.vue'
|
|||
import PropertySelector from '../selectors/PropertySelector.vue'
|
||||
import OperatorSelector from '../selectors/OperatorSelector.vue'
|
||||
import ValueInput from '../inputs/ValueInput.vue'
|
||||
import { TriggerConditionFormData } from '@/api/iot/rule/scene/scene.types'
|
||||
import { TriggerCondition } from '@/api/iot/rule/scene/scene.types'
|
||||
import {
|
||||
IotRuleSceneTriggerConditionTypeEnum,
|
||||
IotRuleSceneTriggerConditionParameterOperatorEnum
|
||||
|
|
@ -133,12 +133,12 @@ import {
|
|||
defineOptions({ name: 'ConditionConfig' })
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: TriggerConditionFormData
|
||||
modelValue: TriggerCondition
|
||||
triggerType: number
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:modelValue', value: TriggerConditionFormData): void
|
||||
(e: 'update:modelValue', value: TriggerCondition): void
|
||||
(e: 'validate', result: { valid: boolean; message: string }): void
|
||||
}>()
|
||||
|
||||
|
|
@ -155,12 +155,12 @@ const isValid = ref(true)
|
|||
const valueValidation = ref({ valid: true, message: '' })
|
||||
|
||||
// 事件处理
|
||||
const updateConditionField = (field: keyof TriggerConditionFormData, value: any) => {
|
||||
const updateConditionField = (field: keyof TriggerCondition, value: any) => {
|
||||
;(condition.value as any)[field] = value
|
||||
emit('update:modelValue', condition.value)
|
||||
}
|
||||
|
||||
const updateCondition = (newCondition: TriggerConditionFormData) => {
|
||||
const updateCondition = (newCondition: TriggerCondition) => {
|
||||
condition.value = newCondition
|
||||
emit('update:modelValue', condition.value)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -320,18 +320,18 @@ import { useVModel } from '@vueuse/core'
|
|||
import { InfoFilled } from '@element-plus/icons-vue'
|
||||
import ProductSelector from '../selectors/ProductSelector.vue'
|
||||
import DeviceSelector from '../selectors/DeviceSelector.vue'
|
||||
import { ActionFormData, ThingModelService } from '@/api/iot/rule/scene/scene.types'
|
||||
import { Action, ThingModelService } from '@/api/iot/rule/scene/scene.types'
|
||||
import { IotRuleSceneActionTypeEnum } from '@/views/iot/utils/constants'
|
||||
|
||||
/** 设备控制配置组件 */
|
||||
defineOptions({ name: 'DeviceControlConfig' })
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: ActionFormData
|
||||
modelValue: Action
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:modelValue', value: ActionFormData): void
|
||||
(e: 'update:modelValue', value: Action): void
|
||||
}>()
|
||||
|
||||
const action = useVModel(props, 'modelValue', emit)
|
||||
|
|
|
|||
|
|
@ -84,17 +84,17 @@
|
|||
import { useVModel } from '@vueuse/core'
|
||||
import ProductSelector from '../selectors/ProductSelector.vue'
|
||||
import DeviceSelector from '../selectors/DeviceSelector.vue'
|
||||
import { TriggerConditionFormData } from '@/api/iot/rule/scene/scene.types'
|
||||
import { TriggerCondition } from '@/api/iot/rule/scene/scene.types'
|
||||
|
||||
/** 设备状态条件配置组件 */
|
||||
defineOptions({ name: 'DeviceStatusConditionConfig' })
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: TriggerConditionFormData
|
||||
modelValue: TriggerCondition
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:modelValue', value: TriggerConditionFormData): void
|
||||
(e: 'update:modelValue', value: TriggerCondition): void
|
||||
(e: 'validate', result: { valid: boolean; message: string }): void
|
||||
}>()
|
||||
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@
|
|||
import { nextTick } from 'vue'
|
||||
import { useVModel } from '@vueuse/core'
|
||||
import ConditionConfig from './ConditionConfig.vue'
|
||||
import { TriggerConditionFormData } from '@/api/iot/rule/scene/scene.types'
|
||||
import { TriggerCondition } from '@/api/iot/rule/scene/scene.types'
|
||||
import {
|
||||
IotRuleSceneTriggerConditionTypeEnum,
|
||||
IotRuleSceneTriggerConditionParameterOperatorEnum
|
||||
|
|
@ -93,13 +93,13 @@ import {
|
|||
defineOptions({ name: 'SubConditionGroupConfig' })
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: TriggerConditionFormData[]
|
||||
modelValue: TriggerCondition[]
|
||||
triggerType: number
|
||||
maxConditions?: number
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:modelValue', value: TriggerConditionFormData[]): void
|
||||
(e: 'update:modelValue', value: TriggerCondition[]): void
|
||||
(e: 'validate', result: { valid: boolean; message: string }): void
|
||||
}>()
|
||||
|
||||
|
|
@ -123,7 +123,7 @@ const addCondition = () => {
|
|||
return
|
||||
}
|
||||
|
||||
const newCondition: TriggerConditionFormData = {
|
||||
const newCondition: TriggerCondition = {
|
||||
type: IotRuleSceneTriggerConditionTypeEnum.DEVICE_PROPERTY, // 默认为设备属性
|
||||
productId: undefined,
|
||||
deviceId: undefined,
|
||||
|
|
@ -161,7 +161,7 @@ const removeCondition = (index: number) => {
|
|||
}
|
||||
}
|
||||
|
||||
const updateCondition = (index: number, condition: TriggerConditionFormData) => {
|
||||
const updateCondition = (index: number, condition: TriggerCondition) => {
|
||||
if (subGroup.value) {
|
||||
subGroup.value[index] = condition
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,12 +78,27 @@
|
|||
@update:model-value="(value) => updateAction(index, value)"
|
||||
/>
|
||||
|
||||
<!-- 告警配置 -->
|
||||
<!-- 告警配置 - 只有恢复告警时才显示 -->
|
||||
<AlertConfig
|
||||
v-if="isAlertAction(action.type)"
|
||||
v-if="action.type === ActionTypeEnum.ALERT_RECOVER"
|
||||
:model-value="action.alertConfigId"
|
||||
@update:model-value="(value) => updateActionAlertConfig(index, value)"
|
||||
/>
|
||||
|
||||
<!-- 触发告警提示 - 触发告警时显示 -->
|
||||
<div
|
||||
v-if="action.type === ActionTypeEnum.ALERT_TRIGGER"
|
||||
class="border border-[var(--el-border-color-light)] rounded-6px p-16px bg-[var(--el-fill-color-blank)]"
|
||||
>
|
||||
<div class="flex items-center gap-8px mb-8px">
|
||||
<Icon icon="ep:warning" class="text-[var(--el-color-warning)] text-16px" />
|
||||
<span class="text-14px font-600 text-[var(--el-text-color-primary)]">触发告警</span>
|
||||
<el-tag size="small" type="warning">自动执行</el-tag>
|
||||
</div>
|
||||
<div class="text-12px text-[var(--el-text-color-secondary)] leading-relaxed">
|
||||
当触发条件满足时,系统将自动发送告警通知,无需额外配置。
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -107,7 +122,7 @@ 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 } from '@/api/iot/rule/scene/scene.types'
|
||||
import { Action } from '@/api/iot/rule/scene/scene.types'
|
||||
import {
|
||||
IotRuleSceneActionTypeEnum as ActionTypeEnum,
|
||||
isDeviceAction,
|
||||
|
|
@ -118,23 +133,20 @@ import {
|
|||
/** 执行器配置组件 */
|
||||
defineOptions({ name: 'ActionSection' })
|
||||
|
||||
interface Props {
|
||||
actions: ActionFormData[]
|
||||
}
|
||||
const props = defineProps<{
|
||||
actions: Action[]
|
||||
}>()
|
||||
|
||||
interface Emits {
|
||||
(e: 'update:actions', value: ActionFormData[]): void
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
const emit = defineEmits<Emits>()
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:actions', value: Action[]): void
|
||||
}>()
|
||||
|
||||
const actions = useVModel(props, 'actions', emit)
|
||||
|
||||
/**
|
||||
* 创建默认的执行器数据
|
||||
*/
|
||||
const createDefaultActionData = (): ActionFormData => {
|
||||
const createDefaultActionData = (): Action => {
|
||||
return {
|
||||
type: ActionTypeEnum.DEVICE_PROPERTY_SET, // 默认为设备属性设置
|
||||
productId: undefined,
|
||||
|
|
@ -145,9 +157,7 @@ const createDefaultActionData = (): ActionFormData => {
|
|||
}
|
||||
}
|
||||
|
||||
// 配置常量
|
||||
// TODO @puhui999:去掉最大;注释风格改下;
|
||||
const maxActions = 5
|
||||
const maxActions = 5 // 最大执行器数量
|
||||
|
||||
// 工具函数
|
||||
const getActionTypeName = (type: number) => {
|
||||
|
|
@ -164,7 +174,7 @@ const getActionTypeTag = (type: number) => {
|
|||
return actionTypeTags[type] || 'info'
|
||||
}
|
||||
|
||||
// 事件处理
|
||||
/** 添加执行器 */
|
||||
const addAction = () => {
|
||||
if (actions.value.length >= maxActions) {
|
||||
return
|
||||
|
|
@ -174,24 +184,29 @@ const addAction = () => {
|
|||
actions.value.push(newAction)
|
||||
}
|
||||
|
||||
/** 删除执行器 */
|
||||
const removeAction = (index: number) => {
|
||||
actions.value.splice(index, 1)
|
||||
}
|
||||
|
||||
/** 更新执行器类型 */
|
||||
const updateActionType = (index: number, type: number) => {
|
||||
actions.value[index].type = type
|
||||
onActionTypeChange(actions.value[index], type)
|
||||
}
|
||||
|
||||
const updateAction = (index: number, action: ActionFormData) => {
|
||||
/** 更新执行器 */
|
||||
const updateAction = (index: number, action: Action) => {
|
||||
actions.value[index] = action
|
||||
}
|
||||
|
||||
/** 更新告警配置 */
|
||||
const updateActionAlertConfig = (index: number, alertConfigId?: number) => {
|
||||
actions.value[index].alertConfigId = alertConfigId
|
||||
}
|
||||
|
||||
const onActionTypeChange = (action: ActionFormData, type: number) => {
|
||||
/** 监听执行器类型变化 */
|
||||
const onActionTypeChange = (action: Action, type: number) => {
|
||||
// 清理不相关的配置,确保数据结构干净
|
||||
if (isDeviceAction(type)) {
|
||||
// 设备控制类型:清理告警配置,确保设备参数存在
|
||||
|
|
@ -204,16 +219,11 @@ const onActionTypeChange = (action: ActionFormData, type: number) => {
|
|||
action.identifier = undefined
|
||||
}
|
||||
} else if (isAlertAction(type)) {
|
||||
// 告警类型:清理设备配置
|
||||
action.productId = undefined
|
||||
action.deviceId = undefined
|
||||
action.identifier = undefined // 清理服务标识符
|
||||
action.params = undefined
|
||||
action.alertConfigId = undefined
|
||||
}
|
||||
|
||||
// 触发重新校验
|
||||
nextTick(() => {
|
||||
// 这里可以添加校验逻辑
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -58,17 +58,17 @@
|
|||
<script setup lang="ts">
|
||||
import { useVModel } from '@vueuse/core'
|
||||
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
|
||||
import { RuleSceneFormData } from '@/api/iot/rule/scene/scene.types'
|
||||
import { IotSceneRule } from '@/api/iot/rule/scene/scene.types'
|
||||
|
||||
/** 基础信息配置组件 */
|
||||
defineOptions({ name: 'BasicInfoSection' })
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: RuleSceneFormData
|
||||
modelValue: IotSceneRule
|
||||
rules?: any
|
||||
}>()
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:modelValue', value: RuleSceneFormData): void
|
||||
(e: 'update:modelValue', value: IotSceneRule): void
|
||||
}>()
|
||||
|
||||
const formData = useVModel(props, 'modelValue', emit)
|
||||
|
|
|
|||
|
|
@ -239,7 +239,7 @@
|
|||
import { DICT_TYPE, getIntDictOptions, getDictLabel } from '@/utils/dict'
|
||||
import { ContentWrap } from '@/components/ContentWrap'
|
||||
import RuleSceneForm from './form/RuleSceneForm.vue'
|
||||
import { IotRuleSceneDO } from '@/api/iot/rule/scene/scene.types'
|
||||
import { IotSceneRule } from '@/api/iot/rule/scene/scene.types'
|
||||
import { RuleSceneApi } from '@/api/iot/rule/scene'
|
||||
import {
|
||||
IotRuleSceneTriggerTypeEnum,
|
||||
|
|
@ -264,14 +264,14 @@ const queryParams = reactive({
|
|||
})
|
||||
|
||||
const loading = ref(true) // 列表的加载中
|
||||
const list = ref<IotRuleSceneDO[]>([]) // 列表的数据
|
||||
const list = ref<IotSceneRule[]>([]) // 列表的数据
|
||||
const total = ref(0) // 列表的总页数
|
||||
const selectedRows = ref<IotRuleSceneDO[]>([]) // 选中的行数据
|
||||
const selectedRows = ref<IotSceneRule[]>([]) // 选中的行数据
|
||||
const queryFormRef = ref() // 搜索的表单
|
||||
|
||||
/** 表单状态 */
|
||||
const formVisible = ref(false) // 是否可见
|
||||
const currentRule = ref<IotRuleSceneDO>() // 表单数据
|
||||
const currentRule = ref<IotSceneRule>() // 表单数据
|
||||
|
||||
/** 统计数据 */
|
||||
const statistics = ref({
|
||||
|
|
@ -327,7 +327,7 @@ const formatCronExpression = (cron: string): string => {
|
|||
}
|
||||
|
||||
/** 获取规则摘要信息 */
|
||||
const getRuleSceneSummary = (rule: IotRuleSceneDO) => {
|
||||
const getRuleSceneSummary = (rule: IotSceneRule) => {
|
||||
const triggerSummary =
|
||||
rule.triggers?.map((trigger: any) => {
|
||||
// 构建基础描述
|
||||
|
|
@ -455,12 +455,12 @@ const updateStatistics = () => {
|
|||
}
|
||||
|
||||
/** 获取触发器摘要 */
|
||||
const getTriggerSummary = (rule: IotRuleSceneDO) => {
|
||||
const getTriggerSummary = (rule: IotSceneRule) => {
|
||||
return getRuleSceneSummary(rule).triggerSummary
|
||||
}
|
||||
|
||||
/** 获取执行器摘要 */
|
||||
const getActionSummary = (rule: IotRuleSceneDO) => {
|
||||
const getActionSummary = (rule: IotSceneRule) => {
|
||||
return getRuleSceneSummary(rule).actionSummary
|
||||
}
|
||||
|
||||
|
|
@ -484,7 +484,7 @@ const handleAdd = () => {
|
|||
}
|
||||
|
||||
/** 修改操作 */
|
||||
const handleEdit = (row: IotRuleSceneDO) => {
|
||||
const handleEdit = (row: IotSceneRule) => {
|
||||
currentRule.value = row
|
||||
formVisible.value = true
|
||||
}
|
||||
|
|
@ -506,7 +506,7 @@ const handleDelete = async (id: number) => {
|
|||
}
|
||||
|
||||
/** 修改状态 */
|
||||
const handleToggleStatus = async (row: IotRuleSceneDO) => {
|
||||
const handleToggleStatus = async (row: IotSceneRule) => {
|
||||
try {
|
||||
// 修改状态的二次确认
|
||||
// TODO @puhui999:status 枚举;
|
||||
|
|
@ -525,7 +525,7 @@ const handleToggleStatus = async (row: IotRuleSceneDO) => {
|
|||
}
|
||||
|
||||
/** 多选框选中数据 */
|
||||
const handleSelectionChange = (selection: IotRuleSceneDO[]) => {
|
||||
const handleSelectionChange = (selection: IotSceneRule[]) => {
|
||||
selectedRows.value = selection
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue