perf:【IoT 物联网】场景联动目录结构优化
This commit is contained in:
104
src/views/iot/rule/scene/form/selectors/ActionTypeSelector.vue
Normal file
104
src/views/iot/rule/scene/form/selectors/ActionTypeSelector.vue
Normal file
@ -0,0 +1,104 @@
|
||||
<!-- 执行器类型选择组件 -->
|
||||
<template>
|
||||
<div class="w-full">
|
||||
<!-- TODO @puhui999:1)设备属性设置时,貌似没选属性;2)服务调用时,貌似也没的设置哈; -->
|
||||
<el-form-item label="执行类型" required>
|
||||
<el-select
|
||||
v-model="localValue"
|
||||
placeholder="请选择执行类型"
|
||||
@change="handleChange"
|
||||
class="w-full"
|
||||
>
|
||||
<el-option
|
||||
v-for="option in actionTypeOptions"
|
||||
:key="option.value"
|
||||
:label="option.label"
|
||||
:value="option.value"
|
||||
>
|
||||
<div class="flex items-center justify-between w-full py-4px">
|
||||
<div class="flex items-center gap-12px flex-1">
|
||||
<Icon :icon="option.icon" class="text-18px text-[var(--el-color-primary)] flex-shrink-0" />
|
||||
<div class="flex-1">
|
||||
<div class="text-14px font-500 text-[var(--el-text-color-primary)] mb-2px">{{ option.label }}</div>
|
||||
<div class="text-12px text-[var(--el-text-color-secondary)] leading-relaxed">{{ option.description }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-tag :type="option.tag" size="small">
|
||||
{{ option.category }}
|
||||
</el-tag>
|
||||
</div>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useVModel } from '@vueuse/core'
|
||||
import { IotRuleSceneActionTypeEnum } from '@/api/iot/rule/scene/scene.types'
|
||||
|
||||
/** 执行器类型选择组件 */
|
||||
defineOptions({ name: 'ActionTypeSelector' })
|
||||
|
||||
interface Props {
|
||||
modelValue: number
|
||||
}
|
||||
|
||||
interface Emits {
|
||||
(e: 'update:modelValue', value: number): void
|
||||
(e: 'change', value: number): void
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
const emit = defineEmits<Emits>()
|
||||
|
||||
const localValue = useVModel(props, 'modelValue', emit)
|
||||
|
||||
// 执行器类型选项
|
||||
const actionTypeOptions = [
|
||||
{
|
||||
value: IotRuleSceneActionTypeEnum.DEVICE_PROPERTY_SET,
|
||||
label: '设备属性设置',
|
||||
description: '设置目标设备的属性值',
|
||||
icon: 'ep:edit',
|
||||
tag: 'primary',
|
||||
category: '设备控制'
|
||||
},
|
||||
{
|
||||
value: IotRuleSceneActionTypeEnum.DEVICE_SERVICE_INVOKE,
|
||||
label: '设备服务调用',
|
||||
description: '调用目标设备的服务',
|
||||
icon: 'ep:service',
|
||||
tag: 'success',
|
||||
category: '设备控制'
|
||||
},
|
||||
{
|
||||
value: IotRuleSceneActionTypeEnum.ALERT_TRIGGER,
|
||||
label: '触发告警',
|
||||
description: '触发系统告警通知',
|
||||
icon: 'ep:warning',
|
||||
tag: 'danger',
|
||||
category: '告警通知'
|
||||
},
|
||||
{
|
||||
value: IotRuleSceneActionTypeEnum.ALERT_RECOVER,
|
||||
label: '恢复告警',
|
||||
description: '恢复已触发的告警',
|
||||
icon: 'ep:circle-check',
|
||||
tag: 'warning',
|
||||
category: '告警通知'
|
||||
}
|
||||
]
|
||||
|
||||
// 事件处理
|
||||
const handleChange = (value: number) => {
|
||||
emit('change', value)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
:deep(.el-select-dropdown__item) {
|
||||
height: auto;
|
||||
padding: 8px 20px;
|
||||
}
|
||||
</style>
|
||||
191
src/views/iot/rule/scene/form/selectors/OperatorSelector.vue
Normal file
191
src/views/iot/rule/scene/form/selectors/OperatorSelector.vue
Normal file
@ -0,0 +1,191 @@
|
||||
<!-- 操作符选择器组件 -->
|
||||
<template>
|
||||
<div class="w-full">
|
||||
<el-select
|
||||
v-model="localValue"
|
||||
placeholder="请选择操作符"
|
||||
@change="handleChange"
|
||||
class="w-full"
|
||||
>
|
||||
<el-option
|
||||
v-for="operator in availableOperators"
|
||||
:key="operator.value"
|
||||
:label="operator.label"
|
||||
:value="operator.value"
|
||||
>
|
||||
<div class="flex items-center justify-between w-full py-4px">
|
||||
<div class="flex items-center gap-8px">
|
||||
<div class="text-14px font-500 text-[var(--el-text-color-primary)]">{{ operator.label }}</div>
|
||||
<div class="text-12px text-[var(--el-color-primary)] bg-[var(--el-color-primary-light-9)] px-6px py-2px rounded-4px font-mono">{{ operator.symbol }}</div>
|
||||
</div>
|
||||
<div class="text-12px text-[var(--el-text-color-secondary)]">{{ operator.description }}</div>
|
||||
</div>
|
||||
</el-option>
|
||||
</el-select>
|
||||
|
||||
<!-- 操作符说明 -->
|
||||
<!-- TODO @puhui999:这个去掉 -->
|
||||
<div v-if="selectedOperator" class="mt-8px p-8px bg-[var(--el-fill-color-light)] rounded-4px border border-[var(--el-border-color-lighter)]">
|
||||
<div class="flex items-center gap-6px">
|
||||
<Icon icon="ep:info-filled" class="text-12px text-[var(--el-color-info)]" />
|
||||
<span class="text-12px text-[var(--el-text-color-secondary)]">{{ selectedOperator.description }}</span>
|
||||
</div>
|
||||
<div v-if="selectedOperator.example" class="flex items-center gap-6px mt-4px">
|
||||
<span class="text-12px text-[var(--el-text-color-secondary)]">示例:</span>
|
||||
<code class="text-12px text-[var(--el-color-primary)] bg-[var(--el-fill-color-blank)] px-4px py-2px rounded-2px font-mono">{{ selectedOperator.example }}</code>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useVModel } from '@vueuse/core'
|
||||
|
||||
/** 操作符选择器组件 */
|
||||
defineOptions({ name: 'OperatorSelector' })
|
||||
|
||||
interface Props {
|
||||
modelValue?: string
|
||||
propertyType?: string
|
||||
}
|
||||
|
||||
interface Emits {
|
||||
(e: 'update:modelValue', value: string): void
|
||||
(e: 'change', value: string): void
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
const emit = defineEmits<Emits>()
|
||||
|
||||
const localValue = useVModel(props, 'modelValue', emit)
|
||||
|
||||
// 所有操作符定义
|
||||
const allOperators = [
|
||||
{
|
||||
value: '=',
|
||||
label: '等于',
|
||||
symbol: '=',
|
||||
description: '值完全相等时触发',
|
||||
example: 'temperature = 25',
|
||||
supportedTypes: ['int', 'float', 'double', 'string', 'bool', 'enum']
|
||||
},
|
||||
{
|
||||
value: '!=',
|
||||
label: '不等于',
|
||||
symbol: '≠',
|
||||
description: '值不相等时触发',
|
||||
example: 'power != false',
|
||||
supportedTypes: ['int', 'float', 'double', 'string', 'bool', 'enum']
|
||||
},
|
||||
{
|
||||
value: '>',
|
||||
label: '大于',
|
||||
symbol: '>',
|
||||
description: '值大于指定值时触发',
|
||||
example: 'temperature > 30',
|
||||
supportedTypes: ['int', 'float', 'double', 'date']
|
||||
},
|
||||
{
|
||||
value: '>=',
|
||||
label: '大于等于',
|
||||
symbol: '≥',
|
||||
description: '值大于或等于指定值时触发',
|
||||
example: 'humidity >= 80',
|
||||
supportedTypes: ['int', 'float', 'double', 'date']
|
||||
},
|
||||
{
|
||||
value: '<',
|
||||
label: '小于',
|
||||
symbol: '<',
|
||||
description: '值小于指定值时触发',
|
||||
example: 'temperature < 10',
|
||||
supportedTypes: ['int', 'float', 'double', 'date']
|
||||
},
|
||||
{
|
||||
value: '<=',
|
||||
label: '小于等于',
|
||||
symbol: '≤',
|
||||
description: '值小于或等于指定值时触发',
|
||||
example: 'battery <= 20',
|
||||
supportedTypes: ['int', 'float', 'double', 'date']
|
||||
},
|
||||
{
|
||||
value: 'in',
|
||||
label: '包含于',
|
||||
symbol: '∈',
|
||||
description: '值在指定列表中时触发',
|
||||
example: 'status in [1,2,3]',
|
||||
supportedTypes: ['int', 'float', 'string', 'enum']
|
||||
},
|
||||
{
|
||||
value: 'between',
|
||||
label: '介于',
|
||||
symbol: '⊆',
|
||||
description: '值在指定范围内时触发',
|
||||
example: 'temperature between 20,30',
|
||||
supportedTypes: ['int', 'float', 'double', 'date']
|
||||
},
|
||||
{
|
||||
value: 'contains',
|
||||
label: '包含',
|
||||
symbol: '⊃',
|
||||
description: '字符串包含指定内容时触发',
|
||||
example: 'message contains "error"',
|
||||
supportedTypes: ['string']
|
||||
},
|
||||
{
|
||||
value: 'startsWith',
|
||||
label: '开始于',
|
||||
symbol: '⊢',
|
||||
description: '字符串以指定内容开始时触发',
|
||||
example: 'deviceName startsWith "sensor"',
|
||||
supportedTypes: ['string']
|
||||
},
|
||||
{
|
||||
value: 'endsWith',
|
||||
label: '结束于',
|
||||
symbol: '⊣',
|
||||
description: '字符串以指定内容结束时触发',
|
||||
example: 'fileName endsWith ".log"',
|
||||
supportedTypes: ['string']
|
||||
}
|
||||
]
|
||||
|
||||
// 计算属性
|
||||
const availableOperators = computed(() => {
|
||||
if (!props.propertyType) {
|
||||
return allOperators
|
||||
}
|
||||
|
||||
return allOperators.filter((op) => op.supportedTypes.includes(props.propertyType!))
|
||||
})
|
||||
|
||||
const selectedOperator = computed(() => {
|
||||
return allOperators.find((op) => op.value === localValue.value)
|
||||
})
|
||||
|
||||
// 事件处理
|
||||
const handleChange = (value: string) => {
|
||||
emit('change', value)
|
||||
}
|
||||
|
||||
// 监听属性类型变化
|
||||
watch(
|
||||
() => props.propertyType,
|
||||
() => {
|
||||
// 如果当前选择的操作符不支持新的属性类型,则清空选择
|
||||
if (localValue.value && selectedOperator.value) {
|
||||
if (!selectedOperator.value.supportedTypes.includes(props.propertyType || '')) {
|
||||
localValue.value = ''
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
:deep(.el-select-dropdown__item) {
|
||||
height: auto;
|
||||
padding: 8px 20px;
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,295 @@
|
||||
<!-- 产品设备选择器组件 -->
|
||||
<template>
|
||||
<div class="product-device-selector">
|
||||
<el-row :gutter="16">
|
||||
<!-- 产品选择 -->
|
||||
<el-col :span="12">
|
||||
<el-form-item label="选择产品" required>
|
||||
<el-select
|
||||
v-model="localProductId"
|
||||
placeholder="请选择产品"
|
||||
filterable
|
||||
clearable
|
||||
@change="handleProductChange"
|
||||
class="w-full"
|
||||
:loading="productLoading"
|
||||
>
|
||||
<el-option
|
||||
v-for="product in productList"
|
||||
:key="product.id"
|
||||
:label="product.name"
|
||||
:value="product.id"
|
||||
>
|
||||
<div class="flex items-center justify-between w-full py-4px">
|
||||
<div class="flex-1">
|
||||
<div class="text-14px font-500 text-[var(--el-text-color-primary)] mb-2px">{{ product.name }}</div>
|
||||
<div class="text-12px text-[var(--el-text-color-secondary)]">{{ product.productKey }}</div>
|
||||
</div>
|
||||
<!-- TODO @puhui999:是不是用字典 -->
|
||||
<el-tag size="small" :type="product.status === 0 ? 'success' : 'danger'">
|
||||
{{ product.status === 0 ? '正常' : '禁用' }}
|
||||
</el-tag>
|
||||
</div>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<!-- 设备选择模式 -->
|
||||
<el-col :span="12">
|
||||
<el-form-item label="设备选择模式" required>
|
||||
<el-radio-group v-model="deviceSelectionMode" @change="handleDeviceSelectionModeChange">
|
||||
<el-radio value="all">全部设备</el-radio>
|
||||
<el-radio value="specific">选择设备</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 具体设备选择 -->
|
||||
<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="请先选择产品"
|
||||
filterable
|
||||
clearable
|
||||
@change="handleDeviceChange"
|
||||
class="w-full"
|
||||
:loading="deviceLoading"
|
||||
:disabled="!localProductId"
|
||||
>
|
||||
<el-option
|
||||
v-for="device in deviceList"
|
||||
:key="device.id"
|
||||
:label="device.deviceName"
|
||||
:value="device.id"
|
||||
>
|
||||
<div class="flex items-center justify-between w-full py-4px">
|
||||
<div class="flex-1">
|
||||
<div class="text-14px font-500 text-[var(--el-text-color-primary)] mb-2px">{{ device.deviceName }}</div>
|
||||
<div class="text-12px text-[var(--el-text-color-secondary)]">{{ device.nickname || '无备注' }}</div>
|
||||
</div>
|
||||
<el-tag size="small" :type="getDeviceStatusTag(device.state)">
|
||||
{{ getDeviceStatusText(device.state) }}
|
||||
</el-tag>
|
||||
</div>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 选择结果展示 -->
|
||||
<div v-if="localProductId && localDeviceId !== undefined" class="mt-16px p-12px bg-[var(--el-fill-color-light)] rounded-6px border border-[var(--el-border-color-lighter)]">
|
||||
<div class="flex items-center gap-6px mb-8px">
|
||||
<Icon icon="ep:check" class="text-[var(--el-color-success)] text-16px" />
|
||||
<span class="text-14px font-500 text-[var(--el-text-color-primary)]">已选择设备</span>
|
||||
</div>
|
||||
<div class="flex flex-col gap-6px ml-22px">
|
||||
<div class="flex items-center gap-8px">
|
||||
<span class="text-12px text-[var(--el-text-color-secondary)] min-w-40px">产品:</span>
|
||||
<span class="text-12px text-[var(--el-text-color-primary)] font-500">{{ selectedProduct?.name }}</span>
|
||||
<el-tag size="small" type="primary">{{ selectedProduct?.productKey }}</el-tag>
|
||||
</div>
|
||||
<div class="flex items-center gap-8px">
|
||||
<span class="text-12px text-[var(--el-text-color-secondary)] min-w-40px">设备:</span>
|
||||
<span v-if="deviceSelectionMode === 'all'" class="text-12px text-[var(--el-text-color-primary)] font-500">全部设备</span>
|
||||
<span v-else class="text-12px text-[var(--el-text-color-primary)] font-500">{{ 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)">
|
||||
{{ getDeviceStatusText(selectedDevice?.state) }}
|
||||
</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useVModel } from '@vueuse/core'
|
||||
import { ProductApi } from '@/api/iot/product/product'
|
||||
import { DeviceApi } from '@/api/iot/device/device'
|
||||
|
||||
/** 产品设备选择器组件 */
|
||||
defineOptions({ name: 'ProductDeviceSelector' })
|
||||
|
||||
interface Props {
|
||||
productId?: number
|
||||
deviceId?: number
|
||||
}
|
||||
|
||||
interface Emits {
|
||||
(e: 'update:productId', value?: number): void
|
||||
(e: 'update:deviceId', value?: number): void
|
||||
(e: 'change', value: { productId?: number; deviceId?: number }): void
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
const emit = defineEmits<Emits>()
|
||||
|
||||
const localProductId = useVModel(props, 'productId', emit)
|
||||
const localDeviceId = useVModel(props, 'deviceId', emit)
|
||||
|
||||
// 设备选择模式
|
||||
// TODO @puhui999:默认选中 all
|
||||
const deviceSelectionMode = ref<'specific' | 'all'>('all')
|
||||
|
||||
// 数据状态
|
||||
const productLoading = ref(false)
|
||||
const deviceLoading = ref(false)
|
||||
const productList = ref<any[]>([])
|
||||
const deviceList = ref<any[]>([])
|
||||
|
||||
// 计算属性
|
||||
const selectedProduct = computed(() => {
|
||||
return productList.value.find((p) => p.id === localProductId.value)
|
||||
})
|
||||
|
||||
const selectedDevice = computed(() => {
|
||||
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 '未知'
|
||||
}
|
||||
}
|
||||
|
||||
const getDeviceStatusTag = (state?: number) => {
|
||||
switch (state) {
|
||||
case 0:
|
||||
return 'info'
|
||||
case 1:
|
||||
return 'success'
|
||||
case 2:
|
||||
return 'danger'
|
||||
default:
|
||||
return 'info'
|
||||
}
|
||||
}
|
||||
|
||||
// 事件处理
|
||||
const handleProductChange = async (productId?: number) => {
|
||||
localProductId.value = productId
|
||||
localDeviceId.value = undefined
|
||||
deviceList.value = []
|
||||
|
||||
if (productId) {
|
||||
await getDeviceList(productId)
|
||||
}
|
||||
|
||||
emitChange()
|
||||
}
|
||||
|
||||
const handleDeviceChange = (deviceId?: number) => {
|
||||
localDeviceId.value = deviceId
|
||||
emitChange()
|
||||
}
|
||||
|
||||
const handleDeviceSelectionModeChange = (mode: 'specific' | 'all') => {
|
||||
deviceSelectionMode.value = mode
|
||||
|
||||
if (mode === 'all') {
|
||||
// 全部设备时,设备 ID 设为 0
|
||||
localDeviceId.value = 0
|
||||
} else {
|
||||
// 选择设备时,清空设备 ID
|
||||
localDeviceId.value = undefined
|
||||
}
|
||||
|
||||
emitChange()
|
||||
}
|
||||
|
||||
const emitChange = () => {
|
||||
emit('change', {
|
||||
productId: localProductId.value,
|
||||
deviceId: localDeviceId.value
|
||||
})
|
||||
}
|
||||
|
||||
// API 调用
|
||||
const getProductList = async () => {
|
||||
productLoading.value = true
|
||||
try {
|
||||
const data = await ProductApi.getSimpleProductList()
|
||||
productList.value = data || []
|
||||
} 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 },
|
||||
{ id: 3, name: '智能门锁', productKey: 'smart_lock_001', status: 0 }
|
||||
]
|
||||
} finally {
|
||||
productLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const getDeviceList = async (productId: number) => {
|
||||
deviceLoading.value = true
|
||||
try {
|
||||
const data = await DeviceApi.getSimpleDeviceList(undefined, productId)
|
||||
deviceList.value = data || []
|
||||
} 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 },
|
||||
{ id: 3, deviceName: 'sensor_003', nickname: '厨房温度传感器', state: 1, productId }
|
||||
]
|
||||
} finally {
|
||||
deviceLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化
|
||||
onMounted(async () => {
|
||||
await getProductList()
|
||||
|
||||
// 根据初始设备 ID 设置选择模式
|
||||
if (localDeviceId.value === 0) {
|
||||
deviceSelectionMode.value = 'all'
|
||||
} else if (localDeviceId.value) {
|
||||
deviceSelectionMode.value = 'specific'
|
||||
}
|
||||
|
||||
if (localProductId.value) {
|
||||
await getDeviceList(localProductId.value)
|
||||
}
|
||||
})
|
||||
|
||||
// 监听产品变化
|
||||
watch(
|
||||
() => localProductId.value,
|
||||
async (newProductId) => {
|
||||
if (newProductId && deviceList.value.length === 0) {
|
||||
await getDeviceList(newProductId)
|
||||
}
|
||||
}
|
||||
)
|
||||
// TODO @puhui999:是不是 unocss
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
:deep(.el-select-dropdown__item) {
|
||||
height: auto;
|
||||
padding: 8px 20px;
|
||||
}
|
||||
</style>
|
||||
343
src/views/iot/rule/scene/form/selectors/PropertySelector.vue
Normal file
343
src/views/iot/rule/scene/form/selectors/PropertySelector.vue
Normal file
@ -0,0 +1,343 @@
|
||||
<!-- 属性选择器组件 -->
|
||||
<!-- TODO @yunai:可能要在 review 下 -->
|
||||
<template>
|
||||
<div class="w-full">
|
||||
<el-select
|
||||
v-model="localValue"
|
||||
placeholder="请选择监控项"
|
||||
filterable
|
||||
clearable
|
||||
@change="handleChange"
|
||||
class="w-full"
|
||||
:loading="loading"
|
||||
>
|
||||
<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"
|
||||
:label="property.name"
|
||||
:value="property.identifier"
|
||||
>
|
||||
<div class="flex items-center justify-between w-full py-4px">
|
||||
<div class="flex-1">
|
||||
<div class="text-14px font-500 text-[var(--el-text-color-primary)] mb-2px">{{ property.name }}</div>
|
||||
<div class="text-12px text-[var(--el-text-color-secondary)]">{{ property.identifier }}</div>
|
||||
</div>
|
||||
<div class="flex-shrink-0">
|
||||
<el-tag :type="getPropertyTypeTag(property.dataType)" size="small">
|
||||
{{ getPropertyTypeName(property.dataType) }}
|
||||
</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
</el-option>
|
||||
</el-option-group>
|
||||
</el-select>
|
||||
|
||||
<!-- 属性详情 -->
|
||||
<div v-if="selectedProperty" class="mt-16px 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-12px">
|
||||
<Icon icon="ep:info-filled" class="text-[var(--el-color-info)] text-16px" />
|
||||
<span class="text-14px font-500 text-[var(--el-text-color-primary)]">{{ selectedProperty.name }}</span>
|
||||
<el-tag :type="getPropertyTypeTag(selectedProperty.dataType)" size="small">
|
||||
{{ getPropertyTypeName(selectedProperty.dataType) }}
|
||||
</el-tag>
|
||||
</div>
|
||||
<div class="space-y-8px ml-24px">
|
||||
<div class="flex items-start gap-8px">
|
||||
<span class="text-12px text-[var(--el-text-color-secondary)] min-w-60px flex-shrink-0">标识符:</span>
|
||||
<span class="text-12px text-[var(--el-text-color-primary)] flex-1">{{ selectedProperty.identifier }}</span>
|
||||
</div>
|
||||
<div v-if="selectedProperty.description" class="flex items-start gap-8px">
|
||||
<span class="text-12px text-[var(--el-text-color-secondary)] min-w-60px flex-shrink-0">描述:</span>
|
||||
<span class="text-12px text-[var(--el-text-color-primary)] flex-1">{{ selectedProperty.description }}</span>
|
||||
</div>
|
||||
<div v-if="selectedProperty.unit" class="flex items-start gap-8px">
|
||||
<span class="text-12px text-[var(--el-text-color-secondary)] min-w-60px flex-shrink-0">单位:</span>
|
||||
<span class="text-12px text-[var(--el-text-color-primary)] flex-1">{{ selectedProperty.unit }}</span>
|
||||
</div>
|
||||
<div v-if="selectedProperty.range" class="flex items-start gap-8px">
|
||||
<span class="text-12px text-[var(--el-text-color-secondary)] min-w-60px flex-shrink-0">取值范围:</span>
|
||||
<span class="text-12px text-[var(--el-text-color-primary)] flex-1">{{ selectedProperty.range }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useVModel } from '@vueuse/core'
|
||||
import { IotRuleSceneTriggerTypeEnum } from '@/api/iot/rule/scene/scene.types'
|
||||
import { ThingModelApi } from '@/api/iot/thingmodel'
|
||||
import { IoTThingModelTypeEnum } from '@/views/iot/utils/constants'
|
||||
import type { IotThingModelTSLRespVO, PropertySelectorItem } from './types'
|
||||
|
||||
/** 属性选择器组件 */
|
||||
defineOptions({ name: 'PropertySelector' })
|
||||
|
||||
interface Props {
|
||||
modelValue?: string
|
||||
triggerType: number
|
||||
productId?: number
|
||||
deviceId?: number
|
||||
}
|
||||
|
||||
interface Emits {
|
||||
(e: 'update:modelValue', value: string): void
|
||||
(e: 'change', value: { type: string; config: any }): void
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
const emit = defineEmits<Emits>()
|
||||
|
||||
const localValue = useVModel(props, 'modelValue', emit)
|
||||
|
||||
// 状态
|
||||
const loading = ref(false)
|
||||
const propertyList = ref<PropertySelectorItem[]>([])
|
||||
const thingModelTSL = ref<IotThingModelTSLRespVO | null>(null)
|
||||
|
||||
// 计算属性
|
||||
const propertyGroups = computed(() => {
|
||||
const groups: { label: string; options: any[] }[] = []
|
||||
|
||||
if (props.triggerType === IotRuleSceneTriggerTypeEnum.DEVICE_PROPERTY_POST) {
|
||||
groups.push({
|
||||
label: '设备属性',
|
||||
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)
|
||||
})
|
||||
}
|
||||
|
||||
if (props.triggerType === IotRuleSceneTriggerTypeEnum.DEVICE_SERVICE_INVOKE) {
|
||||
groups.push({
|
||||
label: '设备服务',
|
||||
options: propertyList.value.filter((p) => p.type === IoTThingModelTypeEnum.SERVICE)
|
||||
})
|
||||
}
|
||||
|
||||
return groups.filter((group) => group.options.length > 0)
|
||||
})
|
||||
|
||||
const selectedProperty = computed(() => {
|
||||
return propertyList.value.find((p) => p.identifier === localValue.value)
|
||||
})
|
||||
|
||||
// 工具函数
|
||||
const getPropertyTypeName = (dataType: string) => {
|
||||
const typeMap = {
|
||||
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'
|
||||
}
|
||||
return tagMap[dataType] || 'info'
|
||||
}
|
||||
|
||||
// 事件处理
|
||||
const handleChange = (value: string) => {
|
||||
const property = propertyList.value.find((p) => p.identifier === value)
|
||||
if (property) {
|
||||
emit('change', {
|
||||
type: property.dataType,
|
||||
config: property
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 获取物模型TSL数据
|
||||
const getThingModelTSL = async () => {
|
||||
if (!props.productId) {
|
||||
thingModelTSL.value = null
|
||||
propertyList.value = []
|
||||
return
|
||||
}
|
||||
|
||||
loading.value = true
|
||||
try {
|
||||
thingModelTSL.value = await ThingModelApi.getThingModelTSLByProductId(props.productId)
|
||||
parseThingModelData()
|
||||
} catch (error) {
|
||||
console.error('获取物模型TSL失败:', error)
|
||||
// 如果TSL获取失败,尝试获取物模型列表
|
||||
await getThingModelList()
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 获取物模型列表(备用方案)
|
||||
const getThingModelList = async () => {
|
||||
if (!props.productId) {
|
||||
propertyList.value = []
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const data = await ThingModelApi.getThingModelList({ productId: props.productId })
|
||||
propertyList.value = data || []
|
||||
} catch (error) {
|
||||
console.error('获取物模型列表失败:', error)
|
||||
propertyList.value = []
|
||||
}
|
||||
}
|
||||
|
||||
// 解析物模型TSL数据
|
||||
const parseThingModelData = () => {
|
||||
const tsl = thingModelTSL.value
|
||||
const properties: PropertySelectorItem[] = []
|
||||
|
||||
if (tsl) {
|
||||
// 解析属性
|
||||
if (tsl.properties && Array.isArray(tsl.properties)) {
|
||||
tsl.properties.forEach((prop) => {
|
||||
properties.push({
|
||||
identifier: prop.identifier,
|
||||
name: prop.name,
|
||||
description: prop.description,
|
||||
dataType: prop.dataType,
|
||||
type: IoTThingModelTypeEnum.PROPERTY,
|
||||
accessMode: prop.accessMode,
|
||||
required: prop.required,
|
||||
unit: getPropertyUnit(prop),
|
||||
range: getPropertyRange(prop),
|
||||
property: prop
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// 解析事件
|
||||
if (tsl.events && Array.isArray(tsl.events)) {
|
||||
tsl.events.forEach((event) => {
|
||||
properties.push({
|
||||
identifier: event.identifier,
|
||||
name: event.name,
|
||||
description: event.description,
|
||||
dataType: 'struct',
|
||||
type: IoTThingModelTypeEnum.EVENT,
|
||||
eventType: event.type,
|
||||
required: event.required,
|
||||
outputParams: event.outputParams,
|
||||
event: event
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// 解析服务
|
||||
if (tsl.services && Array.isArray(tsl.services)) {
|
||||
tsl.services.forEach((service) => {
|
||||
properties.push({
|
||||
identifier: service.identifier,
|
||||
name: service.name,
|
||||
description: service.description,
|
||||
dataType: 'struct',
|
||||
type: IoTThingModelTypeEnum.SERVICE,
|
||||
callType: service.callType,
|
||||
required: service.required,
|
||||
inputParams: service.inputParams,
|
||||
outputParams: service.outputParams,
|
||||
service: service
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
propertyList.value = properties
|
||||
}
|
||||
|
||||
// 获取属性单位
|
||||
const getPropertyUnit = (property: any) => {
|
||||
if (!property) return undefined
|
||||
|
||||
// 数值型数据的单位
|
||||
if (property.dataSpecs && property.dataSpecs.unit) {
|
||||
return property.dataSpecs.unit
|
||||
}
|
||||
|
||||
return undefined
|
||||
}
|
||||
|
||||
// 获取属性范围描述
|
||||
const getPropertyRange = (property: any) => {
|
||||
if (!property) return undefined
|
||||
|
||||
// 数值型数据的范围
|
||||
if (property.dataSpecs) {
|
||||
const specs = property.dataSpecs
|
||||
if (specs.min !== undefined && specs.max !== undefined) {
|
||||
return `${specs.min}~${specs.max}`
|
||||
}
|
||||
}
|
||||
|
||||
// 枚举型和布尔型数据的选项
|
||||
if (property.dataSpecsList && Array.isArray(property.dataSpecsList)) {
|
||||
return property.dataSpecsList.map((item: any) => `${item.name}(${item.value})`).join(', ')
|
||||
}
|
||||
|
||||
return undefined
|
||||
}
|
||||
|
||||
// 获取数据范围描述(保留兼容性)
|
||||
const getDataRange = (dataSpecs: any) => {
|
||||
if (!dataSpecs) return undefined
|
||||
|
||||
if (dataSpecs.min !== undefined && dataSpecs.max !== undefined) {
|
||||
return `${dataSpecs.min}~${dataSpecs.max}`
|
||||
}
|
||||
|
||||
if (dataSpecs.dataSpecsList && Array.isArray(dataSpecs.dataSpecsList)) {
|
||||
return dataSpecs.dataSpecsList.map((item: any) => `${item.name}(${item.value})`).join(', ')
|
||||
}
|
||||
|
||||
return undefined
|
||||
}
|
||||
|
||||
// 监听产品变化
|
||||
watch(
|
||||
() => props.productId,
|
||||
() => {
|
||||
getThingModelTSL()
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
// 监听触发类型变化
|
||||
watch(
|
||||
() => props.triggerType,
|
||||
() => {
|
||||
localValue.value = ''
|
||||
}
|
||||
)
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
:deep(.el-select-dropdown__item) {
|
||||
height: auto;
|
||||
padding: 8px 20px;
|
||||
}
|
||||
</style>
|
||||
142
src/views/iot/rule/scene/form/selectors/TriggerTypeSelector.vue
Normal file
142
src/views/iot/rule/scene/form/selectors/TriggerTypeSelector.vue
Normal file
@ -0,0 +1,142 @@
|
||||
<!-- 触发器类型选择组件 -->
|
||||
<template>
|
||||
<div class="w-full">
|
||||
<el-form-item label="触发类型" required>
|
||||
<el-select
|
||||
v-model="localValue"
|
||||
placeholder="请选择触发类型"
|
||||
@change="handleChange"
|
||||
class="w-full"
|
||||
>
|
||||
<el-option
|
||||
v-for="option in triggerTypeOptions"
|
||||
:key="option.value"
|
||||
:label="option.label"
|
||||
:value="option.value"
|
||||
>
|
||||
<div class="flex items-center justify-between w-full py-4px">
|
||||
<div class="flex items-center gap-12px flex-1">
|
||||
<!-- TODO @puhui999:貌似没对齐? -->
|
||||
<Icon :icon="option.icon" class="text-18px text-[var(--el-color-primary)] flex-shrink-0" />
|
||||
<div class="flex-1">
|
||||
<div class="text-14px font-500 text-[var(--el-text-color-primary)] mb-2px">{{ option.label }}</div>
|
||||
<div class="text-12px text-[var(--el-text-color-secondary)] leading-relaxed">{{ option.description }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- TODO @puhui999:这个要不去掉? -->
|
||||
<el-tag :type="option.tag" size="small">
|
||||
{{ option.category }}
|
||||
</el-tag>
|
||||
</div>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 类型说明 -->
|
||||
<!-- TODO @puhui999:这个去掉。感觉没啥内容哈; -->
|
||||
<div v-if="selectedOption" class="mt-16px p-16px bg-[var(--el-fill-color-light)] rounded-6px border border-[var(--el-border-color-lighter)]">
|
||||
<div class="flex items-center gap-8px mb-12px">
|
||||
<Icon :icon="selectedOption.icon" class="text-20px text-[var(--el-color-primary)]" />
|
||||
<span class="text-16px font-600 text-[var(--el-text-color-primary)]">{{ selectedOption.label }}</span>
|
||||
</div>
|
||||
<div class="ml-28px">
|
||||
<p class="text-14px text-[var(--el-text-color-regular)] m-0 mb-12px leading-relaxed">{{ selectedOption.description }}</p>
|
||||
<div class="flex flex-col gap-6px">
|
||||
<div v-for="feature in selectedOption.features" :key="feature" class="flex items-center gap-6px">
|
||||
<Icon icon="ep:check" class="text-12px text-[var(--el-color-success)] flex-shrink-0" />
|
||||
<span class="text-12px text-[var(--el-text-color-secondary)]">{{ feature }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useVModel } from '@vueuse/core'
|
||||
import { IotRuleSceneTriggerTypeEnum } from '@/api/iot/rule/scene/scene.types'
|
||||
|
||||
/** 触发器类型选择组件 */
|
||||
defineOptions({ name: 'TriggerTypeSelector' })
|
||||
|
||||
interface Props {
|
||||
modelValue: number
|
||||
}
|
||||
|
||||
interface Emits {
|
||||
(e: 'update:modelValue', value: number): void
|
||||
(e: 'change', value: number): void
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
const emit = defineEmits<Emits>()
|
||||
|
||||
const localValue = useVModel(props, 'modelValue', emit)
|
||||
|
||||
// 触发器类型选项
|
||||
const triggerTypeOptions = [
|
||||
{
|
||||
value: IotRuleSceneTriggerTypeEnum.DEVICE_STATE_UPDATE,
|
||||
label: '设备状态变更',
|
||||
description: '当设备上线、离线状态发生变化时触发',
|
||||
icon: 'ep:connection',
|
||||
tag: 'warning',
|
||||
category: '设备状态',
|
||||
features: ['监控设备连接状态', '实时响应设备变化', '无需配置额外条件']
|
||||
},
|
||||
{
|
||||
value: IotRuleSceneTriggerTypeEnum.DEVICE_PROPERTY_POST,
|
||||
label: '设备属性上报',
|
||||
description: '当设备属性值满足指定条件时触发',
|
||||
icon: 'ep:data-line',
|
||||
tag: 'primary',
|
||||
category: '数据监控',
|
||||
features: ['监控设备属性变化', '支持多种比较条件', '可配置阈值范围']
|
||||
},
|
||||
{
|
||||
value: IotRuleSceneTriggerTypeEnum.DEVICE_EVENT_POST,
|
||||
label: '设备事件上报',
|
||||
description: '当设备上报特定事件时触发',
|
||||
icon: 'ep:bell',
|
||||
tag: 'success',
|
||||
category: '事件监控',
|
||||
features: ['监控设备事件', '支持事件参数过滤', '实时事件响应']
|
||||
},
|
||||
{
|
||||
value: IotRuleSceneTriggerTypeEnum.DEVICE_SERVICE_INVOKE,
|
||||
label: '设备服务调用',
|
||||
description: '当设备服务被调用时触发',
|
||||
icon: 'ep:service',
|
||||
tag: 'info',
|
||||
category: '服务监控',
|
||||
features: ['监控服务调用', '支持参数条件', '服务执行跟踪']
|
||||
},
|
||||
{
|
||||
value: IotRuleSceneTriggerTypeEnum.TIMER,
|
||||
label: '定时触发',
|
||||
description: '按照设定的时间计划定时触发',
|
||||
icon: 'ep:timer',
|
||||
tag: 'danger',
|
||||
category: '定时任务',
|
||||
features: ['支持CRON表达式', '灵活的时间配置', '可视化时间设置']
|
||||
}
|
||||
]
|
||||
|
||||
// 计算属性
|
||||
const selectedOption = computed(() => {
|
||||
return triggerTypeOptions.find((option) => option.value === localValue.value)
|
||||
})
|
||||
|
||||
// 事件处理
|
||||
const handleChange = (value: number) => {
|
||||
emit('change', value)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/** TODO @puhui999:unocss 哈 - 已完成转换 */
|
||||
:deep(.el-select-dropdown__item) {
|
||||
height: auto;
|
||||
padding: 8px 20px;
|
||||
}
|
||||
</style>
|
||||
170
src/views/iot/rule/scene/form/selectors/types.ts
Normal file
170
src/views/iot/rule/scene/form/selectors/types.ts
Normal file
@ -0,0 +1,170 @@
|
||||
// IoT物模型TSL数据类型定义
|
||||
|
||||
// TODO @puhui999:看看这些里面,是不是一些已经有了哈?可以复用下~
|
||||
|
||||
/** 物模型TSL响应数据结构 */
|
||||
export interface IotThingModelTSLRespVO {
|
||||
productId: number
|
||||
productKey: string
|
||||
properties: ThingModelProperty[]
|
||||
events: ThingModelEvent[]
|
||||
services: ThingModelService[]
|
||||
}
|
||||
|
||||
/** 物模型属性 */
|
||||
export interface ThingModelProperty {
|
||||
identifier: string
|
||||
name: string
|
||||
accessMode: string
|
||||
required?: boolean
|
||||
dataType: string
|
||||
description?: string
|
||||
dataSpecs?: ThingModelDataSpecs
|
||||
dataSpecsList?: ThingModelDataSpecs[]
|
||||
}
|
||||
|
||||
/** 物模型事件 */
|
||||
export interface ThingModelEvent {
|
||||
identifier: string
|
||||
name: string
|
||||
required?: boolean
|
||||
type: string
|
||||
description?: string
|
||||
outputParams?: ThingModelParam[]
|
||||
method?: string
|
||||
}
|
||||
|
||||
/** 物模型服务 */
|
||||
export interface ThingModelService {
|
||||
identifier: string
|
||||
name: string
|
||||
required?: boolean
|
||||
callType: string
|
||||
description?: string
|
||||
inputParams?: ThingModelParam[]
|
||||
outputParams?: ThingModelParam[]
|
||||
method?: string
|
||||
}
|
||||
|
||||
/** 物模型参数 */
|
||||
export interface ThingModelParam {
|
||||
identifier: string
|
||||
name: string
|
||||
direction: string
|
||||
paraOrder?: number
|
||||
dataType: string
|
||||
dataSpecs?: ThingModelDataSpecs
|
||||
dataSpecsList?: ThingModelDataSpecs[]
|
||||
}
|
||||
|
||||
/** 数值型数据规范 */
|
||||
export interface ThingModelNumericDataSpec {
|
||||
dataType: 'int' | 'float' | 'double'
|
||||
max: string
|
||||
min: string
|
||||
step: string
|
||||
precise?: string
|
||||
defaultValue?: string
|
||||
unit?: string
|
||||
unitName?: string
|
||||
}
|
||||
|
||||
/** 布尔/枚举型数据规范 */
|
||||
export interface ThingModelBoolOrEnumDataSpecs {
|
||||
dataType: 'bool' | 'enum'
|
||||
name: string
|
||||
value: number
|
||||
}
|
||||
|
||||
/** 文本/时间型数据规范 */
|
||||
export interface ThingModelDateOrTextDataSpecs {
|
||||
dataType: 'text' | 'date'
|
||||
length?: number
|
||||
defaultValue?: string
|
||||
}
|
||||
|
||||
/** 数组型数据规范 */
|
||||
export interface ThingModelArrayDataSpecs {
|
||||
dataType: 'array'
|
||||
size: number
|
||||
childDataType: string
|
||||
dataSpecsList?: ThingModelDataSpecs[]
|
||||
}
|
||||
|
||||
/** 结构体型数据规范 */
|
||||
export interface ThingModelStructDataSpecs {
|
||||
dataType: 'struct'
|
||||
identifier: string
|
||||
name: string
|
||||
accessMode: string
|
||||
required?: boolean
|
||||
childDataType: string
|
||||
dataSpecs?: ThingModelDataSpecs
|
||||
dataSpecsList?: ThingModelDataSpecs[]
|
||||
}
|
||||
|
||||
/** 数据规范联合类型 */
|
||||
export type ThingModelDataSpecs =
|
||||
| ThingModelNumericDataSpec
|
||||
| ThingModelBoolOrEnumDataSpecs
|
||||
| ThingModelDateOrTextDataSpecs
|
||||
| ThingModelArrayDataSpecs
|
||||
| ThingModelStructDataSpecs
|
||||
|
||||
/** 属性选择器内部使用的统一数据结构 */
|
||||
export interface PropertySelectorItem {
|
||||
identifier: string
|
||||
name: string
|
||||
description?: string
|
||||
dataType: string
|
||||
type: number // IoTThingModelTypeEnum
|
||||
accessMode?: string
|
||||
required?: boolean
|
||||
unit?: string
|
||||
range?: string
|
||||
eventType?: string
|
||||
callType?: string
|
||||
inputParams?: ThingModelParam[]
|
||||
outputParams?: ThingModelParam[]
|
||||
property?: ThingModelProperty
|
||||
event?: ThingModelEvent
|
||||
service?: ThingModelService
|
||||
}
|
||||
|
||||
/** 数据类型枚举 */
|
||||
export enum DataTypeEnum {
|
||||
INT = 'int',
|
||||
FLOAT = 'float',
|
||||
DOUBLE = 'double',
|
||||
ENUM = 'enum',
|
||||
BOOL = 'bool',
|
||||
TEXT = 'text',
|
||||
DATE = 'date',
|
||||
STRUCT = 'struct',
|
||||
ARRAY = 'array'
|
||||
}
|
||||
|
||||
/** 访问模式枚举 */
|
||||
export enum AccessModeEnum {
|
||||
READ = 'r',
|
||||
READ_write = 'rw'
|
||||
}
|
||||
|
||||
/** 事件类型枚举 */
|
||||
export enum EventTypeEnum {
|
||||
INFO = 'info',
|
||||
ALERT = 'alert',
|
||||
ERROR = 'error'
|
||||
}
|
||||
|
||||
/** 调用类型枚举 */
|
||||
export enum CallTypeEnum {
|
||||
ASYNC = 'async',
|
||||
SYNC = 'sync'
|
||||
}
|
||||
|
||||
/** 参数方向枚举 */
|
||||
export enum ParamDirectionEnum {
|
||||
INPUT = 'input',
|
||||
OUTPUT = 'output'
|
||||
}
|
||||
Reference in New Issue
Block a user