review:【iot 物联网】场景联动的逻辑

pull/812/MERGE
YunaiV 2025-08-09 16:05:48 +08:00
parent c83a2dff93
commit a5478ffcfe
17 changed files with 72 additions and 141 deletions

View File

@ -105,9 +105,7 @@ export const CRON_PRESETS = {
/** CRON 表达式工具类 */ /** CRON 表达式工具类 */
export class CronUtils { export class CronUtils {
/** /** 验证 CRON 表达式格式 */
* CRON
*/
static validate(cronExpression: string): boolean { static validate(cronExpression: string): boolean {
if (!cronExpression || typeof cronExpression !== 'string') { if (!cronExpression || typeof cronExpression !== 'string') {
return false return false
@ -125,9 +123,7 @@ export class CronUtils {
return parts.every((part) => cronRegex.test(part)) return parts.every((part) => cronRegex.test(part))
} }
/** /** 解析单个 CRON 字段 */
* CRON
*/
static parseField( static parseField(
fieldValue: string, fieldValue: string,
fieldType: CronFieldType, fieldType: CronFieldType,
@ -206,9 +202,7 @@ export class CronUtils {
return field return field
} }
/** /** 解析完整的 CRON 表达式 */
* CRON
*/
static parse(cronExpression: string): ParsedCronExpression { static parse(cronExpression: string): ParsedCronExpression {
const result: ParsedCronExpression = { const result: ParsedCronExpression = {
second: { type: 'any', values: [], original: '*', description: '每秒' }, second: { type: 'any', values: [], original: '*', description: '每秒' },
@ -259,9 +253,7 @@ export class CronUtils {
return result return result
} }
/** /** 生成 CRON 表达式的可读描述 */
* CRON
*/
static generateDescription(parsed: ParsedCronExpression): string { static generateDescription(parsed: ParsedCronExpression): string {
const parts: string[] = [] const parts: string[] = []
@ -305,9 +297,7 @@ export class CronUtils {
return parts.length > 0 ? parts.join(' ') : '自定义时间规则' return parts.length > 0 ? parts.join(' ') : '自定义时间规则'
} }
/** /** 格式化 CRON 表达式为可读文本 */
* CRON
*/
static format(cronExpression: string): string { static format(cronExpression: string): string {
if (!cronExpression) return '' if (!cronExpression) return ''
@ -315,9 +305,7 @@ export class CronUtils {
return parsed.isValid ? parsed.description : cronExpression return parsed.isValid ? parsed.description : cronExpression
} }
/** /** 获取预设的 CRON 表达式列表 */
* CRON
*/
static getPresets() { static getPresets() {
return Object.entries(CRON_PRESETS).map(([key, value]) => ({ return Object.entries(CRON_PRESETS).map(([key, value]) => ({
label: this.format(value), label: this.format(value),
@ -326,9 +314,7 @@ export class CronUtils {
})) }))
} }
/** /** 计算 CRON 表达式的下次执行时间 */
* CRON
*/
static getNextExecutionTime(cronExpression: string, fromDate?: Date): Date | null { static getNextExecutionTime(cronExpression: string, fromDate?: Date): Date | null {
const parsed = this.parse(cronExpression) const parsed = this.parse(cronExpression)
if (!parsed.isValid) { if (!parsed.isValid) {
@ -402,9 +388,7 @@ export class CronUtils {
return new Date(now.getTime() + 60000) // 1分钟后 return new Date(now.getTime() + 60000) // 1分钟后
} }
/** /** 获取 CRON 表达式的执行频率描述 */
* CRON
*/
static getFrequencyDescription(cronExpression: string): string { static getFrequencyDescription(cronExpression: string): string {
const parsed = this.parse(cronExpression) const parsed = this.parse(cronExpression)
if (!parsed.isValid) { if (!parsed.isValid) {
@ -435,9 +419,7 @@ export class CronUtils {
return '按计划执行' return '按计划执行'
} }
/** /** 检查 CRON 表达式是否会在指定时间执行 */
* CRON
*/
static willExecuteAt(cronExpression: string, targetDate: Date): boolean { static willExecuteAt(cronExpression: string, targetDate: Date): boolean {
const parsed = this.parse(cronExpression) const parsed = this.parse(cronExpression)
if (!parsed.isValid) { if (!parsed.isValid) {
@ -462,9 +444,7 @@ export class CronUtils {
) )
} }
/** /** 检查字段值是否匹配 */
*
*/
private static fieldMatches(field: ParsedCronField, value: number): boolean { private static fieldMatches(field: ParsedCronField, value: number): boolean {
if (field.type === 'any') { if (field.type === 'any') {
return true return true

View File

@ -14,7 +14,7 @@ import RuleIndex from './rule/index.vue'
import SinkIndex from './sink/index.vue' import SinkIndex from './sink/index.vue'
/** IoT 数据流转 */ /** IoT 数据流转 */
defineOptions({ name: 'IotData' }) defineOptions({ name: 'IoTDataRule' })
const activeTab = ref('rule') const activeTab = ref('rule')
</script> </script>

View File

@ -215,7 +215,6 @@ const validateActions = (_rule: any, value: any, callback: any) => {
} }
const formRules = reactive({ const formRules = reactive({
//
name: [ name: [
{ required: true, message: '场景名称不能为空', trigger: 'blur' }, { required: true, message: '场景名称不能为空', trigger: 'blur' },
{ type: 'string', min: 1, max: 50, message: '场景名称长度应在1-50个字符之间', trigger: 'blur' } { type: 'string', min: 1, max: 50, message: '场景名称长度应在1-50个字符之间', trigger: 'blur' }
@ -234,17 +233,13 @@ const formRules = reactive({
], ],
triggers: [{ required: true, validator: validateTriggers, trigger: 'change' }], triggers: [{ required: true, validator: validateTriggers, trigger: 'change' }],
actions: [{ required: true, validator: validateActions, trigger: 'change' }] actions: [{ required: true, validator: validateActions, trigger: 'change' }]
}) }) //
const submitLoading = ref(false) // const submitLoading = ref(false) //
const isEdit = ref(false) // const isEdit = ref(false) //
const drawerTitle = computed(() => (isEdit.value ? '编辑场景联动规则' : '新增场景联动规则')) //
// /** 提交表单 */
const drawerTitle = computed(() => (isEdit.value ? '编辑场景联动规则' : '新增场景联动规则'))
/**
* 提交表单
*/
const handleSubmit = async () => { const handleSubmit = async () => {
// //
if (!formRef.value) return if (!formRef.value) return
@ -275,16 +270,12 @@ const handleSubmit = async () => {
} }
} }
/** /** 处理抽屉关闭事件 */
* 处理抽屉关闭事件
*/
const handleClose = () => { const handleClose = () => {
drawerVisible.value = false drawerVisible.value = false
} }
/** /** 初始化表单数据 */
* 初始化表单数据
*/
const initFormData = () => { const initFormData = () => {
if (props.ruleScene) { if (props.ruleScene) {
// 使 // 使
@ -316,7 +307,7 @@ const initFormData = () => {
} }
} }
// /** 监听抽屉显示 */
watch(drawerVisible, async (visible) => { watch(drawerVisible, async (visible) => {
if (visible) { if (visible) {
initFormData() initFormData()
@ -326,7 +317,7 @@ watch(drawerVisible, async (visible) => {
} }
}) })
// /** 监听编辑数据变化 */
watch( watch(
() => props.ruleScene, () => props.ruleScene,
() => { () => {

View File

@ -183,14 +183,12 @@ const condition = useVModel(props, 'modelValue', emit)
const propertyType = ref<string>('string') // const propertyType = ref<string>('string') //
const propertyConfig = ref<any>(null) // const propertyConfig = ref<any>(null) //
//
const isDeviceCondition = computed(() => { const isDeviceCondition = computed(() => {
return ( return (
condition.value.type === IotRuleSceneTriggerConditionTypeEnum.DEVICE_STATUS || condition.value.type === IotRuleSceneTriggerConditionTypeEnum.DEVICE_STATUS ||
condition.value.type === IotRuleSceneTriggerConditionTypeEnum.DEVICE_PROPERTY condition.value.type === IotRuleSceneTriggerConditionTypeEnum.DEVICE_PROPERTY
) )
}) }) //
/** /**
* 更新条件字段 * 更新条件字段
@ -240,20 +238,14 @@ const handleConditionTypeChange = (type: number) => {
condition.value.param = '' condition.value.param = ''
} }
/** /** 处理产品变化事件 */
* 处理产品变化事件
* @param _ 产品ID未使用
*/
const handleProductChange = (_: number) => { const handleProductChange = (_: number) => {
// //
condition.value.deviceId = undefined condition.value.deviceId = undefined
condition.value.identifier = '' condition.value.identifier = ''
} }
/** /** 处理设备变化事件 */
* 处理设备变化事件
* @param _ 设备ID未使用
*/
const handleDeviceChange = (_: number) => { const handleDeviceChange = (_: number) => {
// //
condition.value.identifier = '' condition.value.identifier = ''
@ -268,13 +260,11 @@ const handlePropertyChange = (propertyInfo: { type: string; config: any }) => {
propertyConfig.value = propertyInfo.config propertyConfig.value = propertyInfo.config
// //
condition.value.operator = '=' condition.value.operator = IotRuleSceneTriggerConditionParameterOperatorEnum.EQUALS.value
condition.value.param = '' condition.value.param = ''
} }
/** /** 处理操作符变化事件 */
* 处理操作符变化事件
*/
const handleOperatorChange = () => { const handleOperatorChange = () => {
// //
condition.value.param = '' condition.value.param = ''

View File

@ -1,13 +1,6 @@
<!-- 当前时间条件配置组件 --> <!-- 当前时间条件配置组件 -->
<template> <template>
<div class="flex flex-col gap-16px"> <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"
>
<Icon icon="ep:timer" class="text-orange-500 text-18px" />
<span class="text-14px font-500 text-orange-700">当前时间条件配置</span>
</div>
<el-row :gutter="16"> <el-row :gutter="16">
<!-- 时间操作符选择 --> <!-- 时间操作符选择 -->
<el-col :span="8"> <el-col :span="8">
@ -224,7 +217,7 @@ const handleTimeValue2Change = (value: string) => {
condition.value.param = currentParams.slice(0, 2).join(',') condition.value.param = currentParams.slice(0, 2).join(',')
} }
// /** 监听操作符变化,清理不相关的时间值 */
watch( watch(
() => condition.value.operator, () => condition.value.operator,
(newOperator) => { (newOperator) => {

View File

@ -136,7 +136,7 @@ const isServiceInvokeAction = computed(() => {
/** /**
* 处理产品变化事件 * 处理产品变化事件
* @param productId 产品ID * @param productId 产品 ID
*/ */
const handleProductChange = (productId?: number) => { const handleProductChange = (productId?: number) => {
// //
@ -160,7 +160,7 @@ const handleProductChange = (productId?: number) => {
/** /**
* 处理设备变化事件 * 处理设备变化事件
* @param deviceId 设备ID * @param deviceId 设备 ID
*/ */
const handleDeviceChange = (deviceId?: number) => { const handleDeviceChange = (deviceId?: number) => {
// //
@ -338,14 +338,12 @@ const initializeComponent = async () => {
isInitialized.value = true isInitialized.value = true
} }
/** /** 组件初始化 */
* 组件初始化
*/
onMounted(() => { onMounted(() => {
initializeComponent() initializeComponent()
}) })
// /** 监听关键字段的变化,避免深度监听导致的性能问题 */
watch( watch(
() => [action.value.productId, action.value.type, action.value.identifier], () => [action.value.productId, action.value.type, action.value.identifier],
async ([newProductId, , newIdentifier], [oldProductId, , oldIdentifier]) => { async ([newProductId, , newIdentifier], [oldProductId, , oldIdentifier]) => {

View File

@ -205,9 +205,7 @@ const handleTriggerTypeChange = (type: number) => {
emit('trigger-type-change', type) emit('trigger-type-change', type)
} }
/** /** 添加子条件组 */
* 添加子条件组
*/
const addSubGroup = async () => { const addSubGroup = async () => {
if (!trigger.value.conditionGroups) { if (!trigger.value.conditionGroups) {
trigger.value.conditionGroups = [] trigger.value.conditionGroups = []
@ -246,9 +244,7 @@ const updateSubGroup = (index: number, subGroup: any) => {
} }
} }
/** /** 移除整个条件组 */
* 移除整个条件组
*/
const removeConditionGroup = () => { const removeConditionGroup = () => {
trigger.value.conditionGroups = undefined trigger.value.conditionGroups = undefined
} }

View File

@ -295,18 +295,14 @@ const handleTriggerTypeChange = (type: number) => {
emit('trigger-type-change', type) emit('trigger-type-change', type)
} }
/** /** 处理产品变化事件 */
* 处理产品变化事件
*/
const handleProductChange = () => { const handleProductChange = () => {
// //
condition.value.deviceId = undefined condition.value.deviceId = undefined
condition.value.identifier = '' condition.value.identifier = ''
} }
/** /** 处理设备变化事件 */
* 处理设备变化事件
*/
const handleDeviceChange = () => { const handleDeviceChange = () => {
// //
condition.value.identifier = '' condition.value.identifier = ''
@ -331,6 +327,7 @@ const handlePropertyChange = (propertyInfo: any) => {
} }
} }
// TODO @puhui999
/** /**
* 处理操作符变化事件 * 处理操作符变化事件
*/ */

View File

@ -105,9 +105,7 @@ const subGroup = useVModel(props, 'modelValue', emit)
const maxConditions = computed(() => props.maxConditions || 3) // const maxConditions = computed(() => props.maxConditions || 3) //
/** /** 添加条件 */
* 添加条件
*/
const addCondition = async () => { const addCondition = async () => {
// subGroup.value // subGroup.value
if (!subGroup.value) { if (!subGroup.value) {

View File

@ -1,4 +1,5 @@
<!-- 执行器配置组件 --> <!-- 执行器配置组件 -->
<!-- TODO @puhui999每个执行器的 UI 风格应该和触发器配置有点像 -->
<template> <template>
<el-card class="border border-[var(--el-border-color-light)] rounded-8px" shadow="never"> <el-card class="border border-[var(--el-border-color-light)] rounded-8px" shadow="never">
<template #header> <template #header>

View File

@ -137,9 +137,7 @@ const emit = defineEmits<{
const triggers = useVModel(props, 'triggers', emit) const triggers = useVModel(props, 'triggers', emit)
/** /** 添加触发器 */
* 添加触发器
*/
const addTrigger = () => { const addTrigger = () => {
const newTrigger: Trigger = { const newTrigger: Trigger = {
type: TriggerTypeEnum.DEVICE_STATE_UPDATE, type: TriggerTypeEnum.DEVICE_STATE_UPDATE,
@ -184,9 +182,9 @@ const updateTriggerDeviceConfig = (index: number, newTrigger: Trigger) => {
} }
/** /**
* 更新触发器CRON配置 * 更新触发器 CRON 配置
* @param index 触发器索引 * @param index 触发器索引
* @param cronExpression CRON表达式 * @param cronExpression CRON 表达式
*/ */
const updateTriggerCronConfig = (index: number, cronExpression?: string) => { const updateTriggerCronConfig = (index: number, cronExpression?: string) => {
triggers.value[index].cronExpression = cronExpression triggers.value[index].cronExpression = cronExpression
@ -208,7 +206,7 @@ const onTriggerTypeChange = (index: number, _: number) => {
triggerItem.conditionGroups = [] triggerItem.conditionGroups = []
} }
// /** 初始化:确保至少有一个触发器 */
onMounted(() => { onMounted(() => {
if (triggers.value.length === 0) { if (triggers.value.length === 0) {
addTrigger() addTrigger()

View File

@ -18,12 +18,12 @@
> >
<div class="flex items-center justify-between w-full py-4px"> <div class="flex items-center justify-between w-full py-4px">
<div class="flex-1"> <div class="flex-1">
<div class="text-14px font-500 text-[var(--el-text-color-primary)] mb-2px" <div class="text-14px font-500 text-[var(--el-text-color-primary)] mb-2px">
>{{ device.deviceName }} {{ device.deviceName }}
</div> </div>
<div class="text-12px text-[var(--el-text-color-secondary)]">{{ device.deviceKey }}</div> <div class="text-12px text-[var(--el-text-color-secondary)]">{{ device.deviceKey }}</div>
</div> </div>
<div class="flex items-center gap-4px"> <div class="flex items-center gap-4px" v-if="device.id > 0">
<el-tag size="small" :type="getDeviceEnableStatusTagType(device.status)"> <el-tag size="small" :type="getDeviceEnableStatusTagType(device.status)">
{{ getDeviceEnableStatusText(device.status) }} {{ getDeviceEnableStatusText(device.status) }}
</el-tag> </el-tag>
@ -87,7 +87,7 @@ const getDeviceList = async () => {
console.error('获取设备列表失败:', error) console.error('获取设备列表失败:', error)
deviceList.value = [] deviceList.value = []
} finally { } finally {
deviceList.value.push(DEVICE_SELECTOR_OPTIONS.ALL_DEVICES) deviceList.value.unshift(DEVICE_SELECTOR_OPTIONS.ALL_DEVICES)
deviceLoading.value = false deviceLoading.value = false
} }
} }

View File

@ -222,7 +222,6 @@ const availableOperators = computed(() => {
if (!props.propertyType) { if (!props.propertyType) {
return allOperators return allOperators
} }
return allOperators.filter((op) => op.supportedTypes.includes(props.propertyType!)) return allOperators.filter((op) => op.supportedTypes.includes(props.propertyType!))
}) })
@ -239,7 +238,7 @@ const handleChange = (value: string) => {
emit('change', value) emit('change', value)
} }
// /** 监听属性类型变化 */
watch( watch(
() => props.propertyType, () => props.propertyType,
() => { () => {

View File

@ -17,11 +17,11 @@
> >
<div class="flex items-center justify-between w-full py-4px"> <div class="flex items-center justify-between w-full py-4px">
<div class="flex-1"> <div class="flex-1">
<div class="text-14px font-500 text-[var(--el-text-color-primary)] mb-2px" <div class="text-14px font-500 text-[var(--el-text-color-primary)] mb-2px">
>{{ product.name }} {{ product.name }}
</div> </div>
<div class="text-12px text-[var(--el-text-color-secondary)]" <div class="text-12px text-[var(--el-text-color-secondary)]">
>{{ product.productKey }} {{ product.productKey }}
</div> </div>
</div> </div>
<dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="product.status" /> <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="product.status" />
@ -51,16 +51,14 @@ const productList = ref<any[]>([]) // 产品列表
/** /**
* 处理选择变化事件 * 处理选择变化事件
* @param value 选中的产品ID * @param value 选中的产品 ID
*/ */
const handleChange = (value?: number) => { const handleChange = (value?: number) => {
emit('update:modelValue', value) emit('update:modelValue', value)
emit('change', value) emit('change', value)
} }
/** /** 获取产品列表 */
* 获取产品列表
*/
const getProductList = async () => { const getProductList = async () => {
try { try {
productLoading.value = true productLoading.value = true

View File

@ -1,5 +1,4 @@
<!-- 属性选择器组件 --> <!-- 属性选择器组件 -->
<!-- TODO @yunai可能要在 review -->
<template> <template>
<div class="flex items-center gap-8px"> <div class="flex items-center gap-8px">
<el-select <el-select
@ -263,6 +262,7 @@ const handleChange = (value: string) => {
} }
} }
// TODO @puhui999
/** /**
* 获取物模型TSL数据 * 获取物模型TSL数据
*/ */
@ -292,13 +292,12 @@ const getThingModelTSL = async () => {
} }
} }
/** /** 解析物模型 TSL 数据 */
* 解析物模型TSL数据
*/
const parseThingModelData = () => { const parseThingModelData = () => {
const tsl = thingModelTSL.value const tsl = thingModelTSL.value
const properties: PropertySelectorItem[] = [] const properties: PropertySelectorItem[] = []
// TODO @puhui999if return
if (tsl) { if (tsl) {
// //
if (tsl.properties && Array.isArray(tsl.properties)) { if (tsl.properties && Array.isArray(tsl.properties)) {
@ -397,7 +396,7 @@ const getPropertyRange = (property: any) => {
return undefined return undefined
} }
// /** *
watch( watch(
() => props.productId, () => props.productId,
() => { () => {
@ -406,7 +405,7 @@ watch(
{ immediate: true } { immediate: true }
) )
// /** 监听触发类型变化 */
watch( watch(
() => props.triggerType, () => props.triggerType,
() => { () => {

View File

@ -225,14 +225,7 @@
@click="handleToggleStatus(row)" @click="handleToggleStatus(row)"
> >
<Icon :icon="row.status === 0 ? 'ep:video-pause' : 'ep:video-play'" /> <Icon :icon="row.status === 0 ? 'ep:video-pause' : 'ep:video-play'" />
{{ {{ getDictLabel(DICT_TYPE.COMMON_STATUS, row.status) }}
getDictLabel(
DICT_TYPE.COMMON_STATUS,
row.status === CommonStatusEnum.ENABLE
? CommonStatusEnum.DISABLE
: CommonStatusEnum.ENABLE
)
}}
</el-button> </el-button>
<el-button type="danger" class="!mr-10px" link @click="handleDelete(row.id)"> <el-button type="danger" class="!mr-10px" link @click="handleDelete(row.id)">
<Icon icon="ep:delete" /> <Icon icon="ep:delete" />
@ -300,7 +293,7 @@ const statistics = ref({
total: 0, total: 0,
enabled: 0, enabled: 0,
disabled: 0, disabled: 0,
triggered: 0, triggered: 0, // (使)
timerRules: 0 // timerRules: 0 //
}) })
@ -326,14 +319,12 @@ const getRuleSceneSummary = (rule: IotSceneRule) => {
default: default:
description = getTriggerTypeLabel(trigger.type) description = getTriggerTypeLabel(trigger.type)
} }
// //
if (trigger.deviceId) { if (trigger.deviceId) {
description += ` [设备ID: ${trigger.deviceId}]` description += ` [设备ID: ${trigger.deviceId}]`
} else if (trigger.productId) { } else if (trigger.productId) {
description += ` [产品ID: ${trigger.productId}]` description += ` [产品ID: ${trigger.productId}]`
} }
return description return description
}) || [] }) || []
@ -341,19 +332,16 @@ const getRuleSceneSummary = (rule: IotSceneRule) => {
rule.actions?.map((action: any) => { rule.actions?.map((action: any) => {
// //
let description = getActionTypeLabel(action.type) let description = getActionTypeLabel(action.type)
// //
if (action.deviceId) { if (action.deviceId) {
description += ` [设备ID: ${action.deviceId}]` description += ` [设备ID: ${action.deviceId}]`
} else if (action.productId) { } else if (action.productId) {
description += ` [产品ID: ${action.productId}]` description += ` [产品ID: ${action.productId}]`
} }
// //
if (action.alertConfigId) { if (action.alertConfigId) {
description += ` [告警配置ID: ${action.alertConfigId}]` description += ` [告警配置ID: ${action.alertConfigId}]`
} }
return description return description
}) || [] }) || []
@ -383,9 +371,7 @@ const updateStatistics = () => {
total: list.value.length, total: list.value.length,
enabled: list.value.filter((item) => item.status === CommonStatusEnum.ENABLE).length, enabled: list.value.filter((item) => item.status === CommonStatusEnum.ENABLE).length,
disabled: list.value.filter((item) => item.status === CommonStatusEnum.DISABLE).length, disabled: list.value.filter((item) => item.status === CommonStatusEnum.DISABLE).length,
// (使)
triggered: list.value.filter((item) => item.status === CommonStatusEnum.ENABLE).length, triggered: list.value.filter((item) => item.status === CommonStatusEnum.ENABLE).length,
//
timerRules: list.value.filter((item) => hasTimerTrigger(item)).length timerRules: list.value.filter((item) => hasTimerTrigger(item)).length
} }
} }

View File

@ -356,6 +356,7 @@ export const getActionTypeLabel = (type: number): string => {
} }
/** 获取执行器标签类型(用于 el-tag 的 type 属性) */ /** 获取执行器标签类型(用于 el-tag 的 type 属性) */
// TODO @puhui999这种跟界面相关的可以拿到对应组件里
export const getActionTypeTag = ( export const getActionTypeTag = (
type: number type: number
): 'primary' | 'success' | 'info' | 'warning' | 'danger' => { ): 'primary' | 'success' | 'info' | 'warning' | 'danger' => {
@ -368,6 +369,7 @@ export const getActionTypeTag = (
return actionTypeTags[type] || 'info' return actionTypeTags[type] || 'info'
} }
// TODO @puhui999建议不设置最大值哈。
/** 场景联动规则配置常量 */ /** 场景联动规则配置常量 */
export const SCENE_RULE_CONFIG = { export const SCENE_RULE_CONFIG = {
MAX_ACTIONS: 5, // 最大执行器数量 MAX_ACTIONS: 5, // 最大执行器数量
@ -375,6 +377,7 @@ export const SCENE_RULE_CONFIG = {
MAX_CONDITIONS: 20 // 最大条件数量 MAX_CONDITIONS: 20 // 最大条件数量
} as const } as const
// TODO @puhui999下面这个要去掉么
/** IoT 设备消息类型枚举 */ /** IoT 设备消息类型枚举 */
export const IotDeviceMessageTypeEnum = { export const IotDeviceMessageTypeEnum = {
PROPERTY: 'property', // 属性 PROPERTY: 'property', // 属性
@ -434,6 +437,7 @@ export const IoTDeviceStatusEnum = {
} as const } as const
/** 设备启用状态枚举 */ /** 设备启用状态枚举 */
// TODO @puhui999这个是不是和 IoTDeviceStatusEnum 合并下;额外增加一个 value2
export const IoTDeviceEnableStatusEnum = { export const IoTDeviceEnableStatusEnum = {
ENABLED: { ENABLED: {
label: '正常', label: '正常',
@ -448,6 +452,7 @@ export const IoTDeviceEnableStatusEnum = {
} as const } as const
/** 设备激活状态枚举 */ /** 设备激活状态枚举 */
// TODO @puhui999这个是不是搞到界面里。label 就是 IoTDeviceStatusEnum然后 tag 界面里处理;;或者也可以在想想,= = 主要设备状态有 3 个枚举,嘿嘿~
export const IoTDeviceActiveStatusEnum = { export const IoTDeviceActiveStatusEnum = {
ACTIVATED: { ACTIVATED: {
label: '已激活', label: '已激活',
@ -505,11 +510,13 @@ export const deviceStatusChangeOptions = [
/** 获取设备启用状态文本 */ /** 获取设备启用状态文本 */
export const getDeviceEnableStatusText = (status: number): string => { export const getDeviceEnableStatusText = (status: number): string => {
// TODO @puhui999设备有 3 个状态,上线、离线,未激活;
const statusItem = Object.values(IoTDeviceEnableStatusEnum).find((item) => item.value === status) const statusItem = Object.values(IoTDeviceEnableStatusEnum).find((item) => item.value === status)
return statusItem?.label || '未知' return statusItem?.label || '未知'
} }
/** 获取设备启用状态标签类型 */ /** 获取设备启用状态标签类型 */
// TODO @puhui999这个是不是可以直接在界面里处理或者也可以在想想= = 主要设备状态有 3 个枚举,嘿嘿~
export const getDeviceEnableStatusTagType = ( export const getDeviceEnableStatusTagType = (
status: number status: number
): 'primary' | 'success' | 'info' | 'warning' | 'danger' => { ): 'primary' | 'success' | 'info' | 'warning' | 'danger' => {
@ -518,6 +525,7 @@ export const getDeviceEnableStatusTagType = (
} }
/** 获取设备激活状态文本和标签类型 */ /** 获取设备激活状态文本和标签类型 */
// TODO @puhui999这个是不是可以直接在界面里处理或者也可以在想想= = 主要设备状态有 3 个枚举,嘿嘿~
export const getDeviceActiveStatus = (activeTime?: string | null) => { export const getDeviceActiveStatus = (activeTime?: string | null) => {
const isActivated = !!activeTime const isActivated = !!activeTime
return { return {
@ -541,14 +549,13 @@ export const IotRuleSceneTriggerTimeOperatorEnum = {
TODAY: { name: '在今日之间', value: 'today' } // 在今日之间 TODAY: { name: '在今日之间', value: 'today' } // 在今日之间
} as const } as const
// ========== 辅助函数 ==========
/** 获取触发器类型标签 */ /** 获取触发器类型标签 */
export const getTriggerTypeLabel = (type: number): string => { export const getTriggerTypeLabel = (type: number): string => {
const option = triggerTypeOptions.find((item) => item.value === type) const option = triggerTypeOptions.find((item) => item.value === type)
return option?.label || '未知类型' return option?.label || '未知类型'
} }
// TODO @puhui999这种跟界面相关的可以拿到对应组件里
/** 获取触发器标签类型(用于 el-tag 的 type 属性) */ /** 获取触发器标签类型(用于 el-tag 的 type 属性) */
export const getTriggerTagType = ( export const getTriggerTagType = (
type: number type: number
@ -559,9 +566,9 @@ export const getTriggerTagType = (
return isDeviceTrigger(type) ? 'success' : 'info' return isDeviceTrigger(type) ? 'success' : 'info'
} }
// ========== JSON参数输入组件相关常量 ========== // ========== JSON 参数输入组件相关常量 ==========
/** JSON参数输入组件类型枚举 */ /** JSON 参数输入组件类型枚举 */
export const JsonParamsInputTypeEnum = { export const JsonParamsInputTypeEnum = {
SERVICE: 'service', SERVICE: 'service',
EVENT: 'event', EVENT: 'event',
@ -569,11 +576,11 @@ export const JsonParamsInputTypeEnum = {
CUSTOM: 'custom' CUSTOM: 'custom'
} as const } as const
/** JSON参数输入组件类型 */ /** JSON 参数输入组件类型 */
export type JsonParamsInputType = export type JsonParamsInputType =
(typeof JsonParamsInputTypeEnum)[keyof typeof JsonParamsInputTypeEnum] (typeof JsonParamsInputTypeEnum)[keyof typeof JsonParamsInputTypeEnum]
/** JSON参数输入组件文本常量 */ /** JSON 参数输入组件文本常量 */
export const JSON_PARAMS_INPUT_CONSTANTS = { export const JSON_PARAMS_INPUT_CONSTANTS = {
// 基础文本 // 基础文本
PLACEHOLDER: '请输入JSON格式的参数', PLACEHOLDER: '请输入JSON格式的参数',
@ -628,7 +635,7 @@ export const JSON_PARAMS_INPUT_CONSTANTS = {
} }
} as const } as const
/** JSON参数输入组件图标常量 */ /** JSON 参数输入组件图标常量 */
export const JSON_PARAMS_INPUT_ICONS = { export const JSON_PARAMS_INPUT_ICONS = {
// 标题图标 // 标题图标
TITLE_ICONS: { TITLE_ICONS: {
@ -655,7 +662,7 @@ export const JSON_PARAMS_INPUT_ICONS = {
} }
} as const } as const
/** JSON参数输入组件示例值常量 */ /** JSON 参数输入组件示例值常量 */
export const JSON_PARAMS_EXAMPLE_VALUES = { export const JSON_PARAMS_EXAMPLE_VALUES = {
[IoTDataSpecsDataTypeEnum.INT]: { display: '25', value: 25 }, [IoTDataSpecsDataTypeEnum.INT]: { display: '25', value: 25 },
[IoTDataSpecsDataTypeEnum.FLOAT]: { display: '25.5', value: 25.5 }, [IoTDataSpecsDataTypeEnum.FLOAT]: { display: '25.5', value: 25.5 },