perf:【IoT 物联网】场景联动接入后端 api 接口
This commit is contained in:
@ -37,6 +37,7 @@ 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 { RuleSceneApi } from '@/api/iot/rule/scene'
|
||||
import { IotRuleSceneTriggerTypeEnum } from '@/views/iot/utils/constants'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { generateUUID } from '@/utils'
|
||||
@ -55,6 +56,8 @@ defineOptions({ name: 'RuleSceneForm' })
|
||||
const props = defineProps<{
|
||||
/** 抽屉显示状态 */
|
||||
modelValue: boolean
|
||||
/** 编辑的场景联动规则数据 */
|
||||
ruleScene?: IotRuleSceneDO
|
||||
}>()
|
||||
|
||||
/** 组件事件定义 */
|
||||
@ -218,12 +221,13 @@ const handleActionValidate = (result: { valid: boolean; message: string }) => {
|
||||
actionValidation.value = result
|
||||
}
|
||||
|
||||
// TODO @puhui999:API 调用
|
||||
/** 提交表单 */
|
||||
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)
|
||||
@ -237,28 +241,22 @@ const handleSubmit = async () => {
|
||||
// 提交请求
|
||||
submitLoading.value = true
|
||||
try {
|
||||
console.log(formData.value)
|
||||
// 转换数据格式
|
||||
const apiData = convertFormToVO(formData.value)
|
||||
if (true) {
|
||||
console.log('转换后', apiData)
|
||||
return
|
||||
}
|
||||
console.log('提交数据:', apiData)
|
||||
|
||||
// 调用API保存数据
|
||||
if (isEdit.value) {
|
||||
// 更新场景联动规则
|
||||
// await RuleSceneApi.updateRuleScene(apiData)
|
||||
console.log('更新数据:', apiData)
|
||||
await RuleSceneApi.updateRuleScene(apiData)
|
||||
ElMessage.success('更新成功')
|
||||
} else {
|
||||
// 创建场景联动规则
|
||||
// await RuleSceneApi.createRuleScene(apiData)
|
||||
console.log('创建数据:', apiData)
|
||||
await RuleSceneApi.createRuleScene(apiData)
|
||||
ElMessage.success('创建成功')
|
||||
}
|
||||
|
||||
// 模拟API调用
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000))
|
||||
|
||||
ElMessage.success(isEdit.value ? '更新成功' : '创建成功')
|
||||
// 关闭抽屉并触发成功事件
|
||||
drawerVisible.value = false
|
||||
emit('success')
|
||||
} catch (error) {
|
||||
@ -275,28 +273,36 @@ const handleClose = () => {
|
||||
|
||||
/** 初始化表单数据 */
|
||||
const initFormData = () => {
|
||||
// TODO @puhui999: 编辑的情况后面实现
|
||||
formData.value = createDefaultFormData()
|
||||
if (props.ruleScene) {
|
||||
// 编辑模式:转换后端数据为表单格式
|
||||
isEdit.value = true
|
||||
formData.value = convertVOToForm(props.ruleScene)
|
||||
} else {
|
||||
// 新增模式:使用默认数据
|
||||
isEdit.value = false
|
||||
formData.value = createDefaultFormData()
|
||||
}
|
||||
}
|
||||
|
||||
// 监听抽屉显示
|
||||
watch(drawerVisible, (visible) => {
|
||||
if (visible) {
|
||||
initFormData()
|
||||
// TODO @puhui999: 重置表单的情况
|
||||
// nextTick(() => {
|
||||
// formRef.value?.clearValidate()
|
||||
// })
|
||||
// 重置表单验证状态
|
||||
nextTick(() => {
|
||||
formRef.value?.clearValidate()
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// 监听 props 变化
|
||||
// watch(
|
||||
// () => props.ruleScene,
|
||||
// () => {
|
||||
// if (drawerVisible.value) {
|
||||
// initFormData()
|
||||
// }
|
||||
// }
|
||||
// )
|
||||
// 监听编辑数据变化
|
||||
watch(
|
||||
() => props.ruleScene,
|
||||
() => {
|
||||
if (drawerVisible.value) {
|
||||
initFormData()
|
||||
}
|
||||
},
|
||||
{ deep: true }
|
||||
)
|
||||
</script>
|
||||
|
||||
@ -164,7 +164,7 @@
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!-- TODO puhui999:貌似展示不太对劲。。。一个字,一个 tab 哈了。 -->
|
||||
<!-- 触发条件列 -->
|
||||
<el-table-column label="触发条件" min-width="250">
|
||||
<template #default="{ row }">
|
||||
<div class="flex flex-wrap gap-4px">
|
||||
@ -180,7 +180,7 @@
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!-- TODO puhui999:貌似展示不太对劲。。。一个字,一个 tab 哈了。 -->
|
||||
<!-- 执行动作列 -->
|
||||
<el-table-column label="执行动作" min-width="250">
|
||||
<template #default="{ row }">
|
||||
<div class="flex flex-wrap gap-4px">
|
||||
@ -222,8 +222,7 @@
|
||||
@click="handleToggleStatus(row)"
|
||||
>
|
||||
<Icon :icon="row.status === 0 ? 'ep:video-pause' : 'ep:video-play'" />
|
||||
<!-- TODO @puhui999:字典翻译 -->
|
||||
{{ row.status === 0 ? '禁用' : '启用' }}
|
||||
{{ getDictLabel(DICT_TYPE.COMMON_STATUS, row.status === 0 ? 1 : 0) }}
|
||||
</el-button>
|
||||
<el-button type="danger" class="!mr-10px" link @click="handleDelete(row.id)">
|
||||
<Icon icon="ep:delete" />
|
||||
@ -270,15 +269,22 @@
|
||||
</div>
|
||||
|
||||
<!-- 表单对话框 -->
|
||||
<RuleSceneForm v-model="formVisible" @success="getList" />
|
||||
<RuleSceneForm v-model="formVisible" :rule-scene="currentRule" @success="getList" />
|
||||
</ContentWrap>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
|
||||
import { DICT_TYPE, getIntDictOptions, getDictLabel } from '@/utils/dict'
|
||||
import { ContentWrap } from '@/components/ContentWrap'
|
||||
import RuleSceneForm from './form/RuleSceneForm.vue'
|
||||
import { IotRuleScene } from '@/api/iot/rule/scene/scene.types'
|
||||
import { RuleSceneApi } from '@/api/iot/rule/scene'
|
||||
import {
|
||||
IotRuleSceneTriggerTypeEnum,
|
||||
IotRuleSceneActionTypeEnum,
|
||||
getTriggerTypeLabel,
|
||||
getActionTypeLabel
|
||||
} from '@/views/iot/utils/constants'
|
||||
import { formatDate } from '@/utils/formatTime'
|
||||
|
||||
/** 场景联动规则管理页面 */
|
||||
@ -314,7 +320,7 @@ const statistics = ref({
|
||||
})
|
||||
|
||||
/** 格式化 CRON 表达式显示 */
|
||||
// TODO @puhui999:这个能不能 cron 组件里翻译哈;
|
||||
// 注:后续可考虑将此功能移至 CRON 组件内部
|
||||
const formatCronExpression = (cron: string): string => {
|
||||
if (!cron) return ''
|
||||
|
||||
@ -359,39 +365,37 @@ const formatCronExpression = (cron: string): string => {
|
||||
|
||||
/** 获取规则摘要信息 */
|
||||
const getRuleSceneSummary = (rule: IotRuleScene) => {
|
||||
// TODO @puhui999:是不是可以使用字段,或者枚举?
|
||||
const triggerSummary =
|
||||
rule.triggers?.map((trigger) => {
|
||||
switch (trigger.type) {
|
||||
case 1:
|
||||
case IotRuleSceneTriggerTypeEnum.DEVICE_STATE_UPDATE:
|
||||
return `设备状态变更 (${trigger.deviceNames?.length || 0}个设备)`
|
||||
case 2:
|
||||
case IotRuleSceneTriggerTypeEnum.DEVICE_PROPERTY_POST:
|
||||
return `属性上报 (${trigger.deviceNames?.length || 0}个设备)`
|
||||
case 3:
|
||||
case IotRuleSceneTriggerTypeEnum.DEVICE_EVENT_POST:
|
||||
return `事件上报 (${trigger.deviceNames?.length || 0}个设备)`
|
||||
case 4:
|
||||
case IotRuleSceneTriggerTypeEnum.DEVICE_SERVICE_INVOKE:
|
||||
return `服务调用 (${trigger.deviceNames?.length || 0}个设备)`
|
||||
case 100:
|
||||
case IotRuleSceneTriggerTypeEnum.TIMER:
|
||||
return `定时触发 (${formatCronExpression(trigger.cronExpression || '')})`
|
||||
default:
|
||||
return '未知触发类型'
|
||||
return getTriggerTypeLabel(trigger.type)
|
||||
}
|
||||
}) || []
|
||||
|
||||
// TODO @puhui999:是不是可以使用字段,或者枚举?
|
||||
const actionSummary =
|
||||
rule.actions?.map((action) => {
|
||||
switch (action.type) {
|
||||
case 1:
|
||||
case IotRuleSceneActionTypeEnum.DEVICE_PROPERTY_SET:
|
||||
return `设备属性设置 (${action.deviceControl?.deviceNames?.length || 0}个设备)`
|
||||
case 2:
|
||||
case IotRuleSceneActionTypeEnum.DEVICE_SERVICE_INVOKE:
|
||||
return `设备服务调用 (${action.deviceControl?.deviceNames?.length || 0}个设备)`
|
||||
case 100:
|
||||
case IotRuleSceneActionTypeEnum.ALERT_TRIGGER:
|
||||
return '发送告警通知'
|
||||
case 101:
|
||||
case IotRuleSceneActionTypeEnum.ALERT_RECOVER:
|
||||
return '发送邮件通知'
|
||||
default:
|
||||
return '未知执行类型'
|
||||
return getActionTypeLabel(action.type)
|
||||
}
|
||||
}) || []
|
||||
|
||||
@ -402,69 +406,26 @@ const getRuleSceneSummary = (rule: IotRuleScene) => {
|
||||
}
|
||||
|
||||
/** 查询列表 */
|
||||
// TODO @puhui999:这里使用真实数据;
|
||||
const getList = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
// 模拟API调用
|
||||
const mockData = {
|
||||
list: [
|
||||
{
|
||||
id: 1,
|
||||
name: '温度过高自动降温',
|
||||
description: '当温度超过30度时自动开启空调',
|
||||
status: 0,
|
||||
triggers: [
|
||||
{
|
||||
type: 2,
|
||||
productKey: 'temp_sensor',
|
||||
deviceNames: ['sensor_001'],
|
||||
conditions: [
|
||||
{
|
||||
type: 'property',
|
||||
identifier: 'temperature',
|
||||
parameters: [{ operator: '>', value: '30' }]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
actions: [
|
||||
{
|
||||
type: 1,
|
||||
deviceControl: {
|
||||
productKey: 'air_conditioner',
|
||||
deviceNames: ['ac_001'],
|
||||
type: 'property',
|
||||
identifier: 'power',
|
||||
params: { power: 1 }
|
||||
}
|
||||
}
|
||||
],
|
||||
lastTriggeredTime: new Date().toISOString(),
|
||||
createTime: new Date().toISOString()
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: '设备离线告警',
|
||||
description: '设备离线时发送告警通知',
|
||||
status: 0,
|
||||
triggers: [
|
||||
{ type: 1, productKey: 'smart_device', deviceNames: ['device_001', 'device_002'] }
|
||||
],
|
||||
actions: [{ type: 100, alertConfigId: 1 }],
|
||||
createTime: new Date().toISOString()
|
||||
}
|
||||
],
|
||||
total: 2
|
||||
}
|
||||
|
||||
list.value = mockData.list
|
||||
total.value = mockData.total
|
||||
// 调用真实API获取数据
|
||||
const data = await RuleSceneApi.getRuleScenePage(queryParams)
|
||||
list.value = data.list
|
||||
total.value = data.total
|
||||
|
||||
// 更新统计数据
|
||||
updateStatistics()
|
||||
} catch (error) {
|
||||
console.error('获取列表失败:', error)
|
||||
ElMessage.error('获取列表失败')
|
||||
|
||||
// 清空列表数据
|
||||
list.value = []
|
||||
total.value = 0
|
||||
|
||||
// 更新统计数据
|
||||
updateStatistics()
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
@ -476,8 +437,8 @@ const updateStatistics = () => {
|
||||
total: list.value.length,
|
||||
enabled: list.value.filter((item) => item.status === 0).length,
|
||||
disabled: list.value.filter((item) => item.status === 1).length,
|
||||
// TODO @puhui999:这里缺了 lastTriggeredTime 定义
|
||||
triggered: list.value.filter((item) => item.lastTriggeredTime).length
|
||||
// 已触发的规则数量 (暂时使用启用状态的规则数量)
|
||||
triggered: list.value.filter((item) => item.status === 0).length
|
||||
}
|
||||
}
|
||||
|
||||
@ -517,19 +478,19 @@ const handleEdit = (row: IotRuleScene) => {
|
||||
}
|
||||
|
||||
/** 删除按钮操作 */
|
||||
// TODO @puhui999:貌似 id 没用上
|
||||
const handleDelete = async (id: number) => {
|
||||
try {
|
||||
// 删除的二次确认
|
||||
await message.delConfirm()
|
||||
// 发起删除
|
||||
// await RuleSceneApi.deleteRuleScene(id)
|
||||
|
||||
// 模拟删除操作
|
||||
await RuleSceneApi.deleteRuleScene(id)
|
||||
message.success(t('common.delSuccess'))
|
||||
// 刷新列表
|
||||
await getList()
|
||||
} catch {}
|
||||
} catch (error) {
|
||||
console.error('删除失败:', error)
|
||||
ElMessage.error('删除失败')
|
||||
}
|
||||
}
|
||||
|
||||
/** 修改状态 */
|
||||
@ -539,10 +500,10 @@ const handleToggleStatus = async (row: IotRuleScene) => {
|
||||
const text = row.status === 0 ? '禁用' : '启用'
|
||||
await message.confirm('确认要' + text + '"' + row.name + '"吗?')
|
||||
// 发起修改状态
|
||||
// TODO @puhui999:这里缺了
|
||||
// 调用API更新状态 (待后端API实现)
|
||||
// await RuleSceneApi.updateRuleSceneStatus(row.id, row.status === 0 ? 1 : 0)
|
||||
|
||||
// 模拟状态切换
|
||||
// 更新本地状态
|
||||
row.status = row.status === 0 ? 1 : 0
|
||||
message.success(text + '成功')
|
||||
// 刷新统计
|
||||
@ -563,7 +524,7 @@ const handleBatchEnable = async () => {
|
||||
try {
|
||||
await message.confirm(`确定要启用选中的 ${selectedRows.value.length} 个规则吗?`)
|
||||
// 这里应该调用批量启用API
|
||||
// TODO @puhui999:这里缺了
|
||||
// 批量启用API调用 (待后端API实现)
|
||||
// await RuleSceneApi.updateRuleSceneStatusBatch(selectedRows.value.map(row => row.id), 0)
|
||||
|
||||
// 模拟批量启用
|
||||
@ -580,7 +541,7 @@ const handleBatchDisable = async () => {
|
||||
try {
|
||||
await message.confirm(`确定要禁用选中的 ${selectedRows.value.length} 个规则吗?`)
|
||||
// 这里应该调用批量禁用API
|
||||
// TODO @puhui999:这里缺了
|
||||
// 批量禁用API调用 (待后端API实现)
|
||||
// await RuleSceneApi.updateRuleSceneStatusBatch(selectedRows.value.map(row => row.id), 1)
|
||||
|
||||
// 模拟批量禁用
|
||||
@ -599,8 +560,8 @@ const handleBatchDelete = async () => {
|
||||
type: 'warning'
|
||||
})
|
||||
|
||||
// TODO @puhui999:这里缺了
|
||||
// 这里应该调用批量删除API
|
||||
// 批量删除API调用 (待后端API实现)
|
||||
// await RuleSceneApi.deleteRuleSceneBatch(selectedRows.value.map(row => row.id))
|
||||
message.success('批量删除成功')
|
||||
await getList()
|
||||
} catch (error) {}
|
||||
|
||||
@ -300,3 +300,24 @@ export const IotRuleSceneTriggerTimeOperatorEnum = {
|
||||
AFTER_TODAY: { name: '在今日之后', value: 'after_today' }, // 在今日之后
|
||||
TODAY: { name: '在今日之间', value: 'today' } // 在今日之间
|
||||
} as const
|
||||
|
||||
// ========== 辅助函数 ==========
|
||||
|
||||
/** 获取触发器类型标签 */
|
||||
export const getTriggerTypeLabel = (type: number): string => {
|
||||
const options = getTriggerTypeOptions()
|
||||
const option = options.find((item) => item.value === type)
|
||||
return option?.label || '未知类型'
|
||||
}
|
||||
|
||||
/** 获取执行器类型标签 */
|
||||
export const getActionTypeLabel = (type: number): string => {
|
||||
const actionTypeOptions = [
|
||||
{ label: '设备属性设置', value: IotRuleSceneActionTypeEnum.DEVICE_PROPERTY_SET },
|
||||
{ label: '设备服务调用', value: IotRuleSceneActionTypeEnum.DEVICE_SERVICE_INVOKE },
|
||||
{ label: '告警触发', value: IotRuleSceneActionTypeEnum.ALERT_TRIGGER },
|
||||
{ label: '告警恢复', value: IotRuleSceneActionTypeEnum.ALERT_RECOVER }
|
||||
]
|
||||
const option = actionTypeOptions.find((item) => item.value === type)
|
||||
return option?.label || '未知类型'
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user