2025-10-07 19:58:59 +08:00
|
|
|
|
<!-- 产品的物模型表单 -->
|
2025-10-10 20:26:17 +08:00
|
|
|
|
<script lang="ts" setup>
|
|
|
|
|
|
import type { Ref } from 'vue';
|
2025-10-07 19:58:59 +08:00
|
|
|
|
|
2025-10-13 10:17:19 +08:00
|
|
|
|
import type { IotProductApi } from '#/api/iot/product/product';
|
2025-10-10 20:26:17 +08:00
|
|
|
|
import type { ThingModelData } from '#/api/iot/thingmodel';
|
2025-10-07 19:58:59 +08:00
|
|
|
|
|
2025-10-10 20:26:17 +08:00
|
|
|
|
import { inject, ref } from 'vue';
|
|
|
|
|
|
|
2025-10-13 10:17:19 +08:00
|
|
|
|
import { DICT_TYPE } from '@vben/constants';
|
|
|
|
|
|
import { getDictOptions } from '@vben/hooks';
|
|
|
|
|
|
import { $t } from '@vben/locales';
|
|
|
|
|
|
import { cloneDeep } from '@vben/utils';
|
2025-10-10 20:26:17 +08:00
|
|
|
|
|
|
|
|
|
|
import { message } from 'ant-design-vue';
|
|
|
|
|
|
|
2025-10-13 10:17:19 +08:00
|
|
|
|
import { createThingModel, updateThingModel } from '#/api/iot/thingmodel';
|
2025-10-07 19:58:59 +08:00
|
|
|
|
import {
|
|
|
|
|
|
IOT_PROVIDE_KEY,
|
|
|
|
|
|
IoTDataSpecsDataTypeEnum,
|
2025-10-10 20:26:17 +08:00
|
|
|
|
IoTThingModelTypeEnum,
|
|
|
|
|
|
} from '#/views/iot/utils/constants';
|
|
|
|
|
|
|
|
|
|
|
|
import ThingModelEvent from './ThingModelEvent.vue';
|
|
|
|
|
|
import ThingModelProperty from './ThingModelProperty.vue';
|
|
|
|
|
|
import ThingModelService from './ThingModelService.vue';
|
2025-10-07 19:58:59 +08:00
|
|
|
|
|
|
|
|
|
|
/** IoT 物模型数据表单 */
|
2025-10-10 20:26:17 +08:00
|
|
|
|
defineOptions({ name: 'IoTThingModelForm' });
|
2025-10-07 19:58:59 +08:00
|
|
|
|
|
2025-10-10 20:26:17 +08:00
|
|
|
|
/** 提交表单 */
|
|
|
|
|
|
const emit = defineEmits(['success']);
|
2025-10-13 10:17:19 +08:00
|
|
|
|
const product = inject<Ref<IotProductApi.Product>>(IOT_PROVIDE_KEY.PRODUCT); // 注入产品信息
|
2025-10-07 19:58:59 +08:00
|
|
|
|
|
2025-10-10 20:26:17 +08:00
|
|
|
|
const dialogVisible = ref(false); // 弹窗的是否展示
|
|
|
|
|
|
const dialogTitle = ref(''); // 弹窗的标题
|
|
|
|
|
|
const formLoading = ref(false); // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
|
|
|
|
|
|
const formType = ref(''); // 表单的类型:create - 新增;update - 修改
|
2025-10-07 19:58:59 +08:00
|
|
|
|
const formData = ref<ThingModelData>({
|
|
|
|
|
|
type: IoTThingModelTypeEnum.PROPERTY,
|
|
|
|
|
|
dataType: IoTDataSpecsDataTypeEnum.INT,
|
|
|
|
|
|
property: {
|
|
|
|
|
|
dataType: IoTDataSpecsDataTypeEnum.INT,
|
|
|
|
|
|
dataSpecs: {
|
2025-10-10 20:26:17 +08:00
|
|
|
|
dataType: IoTDataSpecsDataTypeEnum.INT,
|
|
|
|
|
|
},
|
2025-10-07 19:58:59 +08:00
|
|
|
|
},
|
|
|
|
|
|
service: {},
|
2025-10-10 20:26:17 +08:00
|
|
|
|
event: {},
|
|
|
|
|
|
} as ThingModelData);
|
2025-10-07 19:58:59 +08:00
|
|
|
|
|
2025-10-10 20:26:17 +08:00
|
|
|
|
const formRef = ref(); // 表单 Ref
|
2025-10-07 19:58:59 +08:00
|
|
|
|
|
|
|
|
|
|
/** 打开弹窗 */
|
|
|
|
|
|
const open = async (type: string, id?: number) => {
|
2025-10-10 20:26:17 +08:00
|
|
|
|
dialogVisible.value = true;
|
2025-10-13 10:17:19 +08:00
|
|
|
|
dialogTitle.value = $t(`action.${type}`);
|
2025-10-10 20:26:17 +08:00
|
|
|
|
formType.value = type;
|
|
|
|
|
|
resetForm();
|
2025-10-07 19:58:59 +08:00
|
|
|
|
if (id) {
|
2025-10-10 20:26:17 +08:00
|
|
|
|
formLoading.value = true;
|
2025-10-07 19:58:59 +08:00
|
|
|
|
try {
|
2025-10-13 10:17:19 +08:00
|
|
|
|
formData.value = await getThingModel(id);
|
2025-10-07 19:58:59 +08:00
|
|
|
|
// 情况一:属性初始化
|
2025-10-10 20:26:17 +08:00
|
|
|
|
if (
|
|
|
|
|
|
!formData.value.property ||
|
|
|
|
|
|
Object.keys(formData.value.property).length === 0
|
|
|
|
|
|
) {
|
|
|
|
|
|
formData.value.dataType = IoTDataSpecsDataTypeEnum.INT;
|
2025-10-07 19:58:59 +08:00
|
|
|
|
formData.value.property = {
|
|
|
|
|
|
dataType: IoTDataSpecsDataTypeEnum.INT,
|
|
|
|
|
|
dataSpecs: {
|
2025-10-10 20:26:17 +08:00
|
|
|
|
dataType: IoTDataSpecsDataTypeEnum.INT,
|
|
|
|
|
|
},
|
|
|
|
|
|
};
|
2025-10-07 19:58:59 +08:00
|
|
|
|
}
|
|
|
|
|
|
// 情况二:服务初始化
|
2025-10-10 20:26:17 +08:00
|
|
|
|
if (
|
|
|
|
|
|
!formData.value.service ||
|
|
|
|
|
|
Object.keys(formData.value.service).length === 0
|
|
|
|
|
|
) {
|
|
|
|
|
|
formData.value.service = {};
|
2025-10-07 19:58:59 +08:00
|
|
|
|
}
|
|
|
|
|
|
// 情况三:事件初始化
|
2025-10-10 20:26:17 +08:00
|
|
|
|
if (
|
|
|
|
|
|
!formData.value.event ||
|
|
|
|
|
|
Object.keys(formData.value.event).length === 0
|
|
|
|
|
|
) {
|
|
|
|
|
|
formData.value.event = {};
|
2025-10-07 19:58:59 +08:00
|
|
|
|
}
|
|
|
|
|
|
} finally {
|
2025-10-10 20:26:17 +08:00
|
|
|
|
formLoading.value = false;
|
2025-10-07 19:58:59 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-10-10 20:26:17 +08:00
|
|
|
|
};
|
|
|
|
|
|
defineExpose({ open, close: () => (dialogVisible.value = false) });
|
2025-10-07 19:58:59 +08:00
|
|
|
|
|
2025-10-13 10:17:19 +08:00
|
|
|
|
async function submitForm() {
|
2025-10-10 20:26:17 +08:00
|
|
|
|
await formRef.value.validate();
|
|
|
|
|
|
formLoading.value = true;
|
2025-10-07 19:58:59 +08:00
|
|
|
|
try {
|
2025-10-10 20:26:17 +08:00
|
|
|
|
const data = cloneDeep(formData.value) as ThingModelData;
|
2025-10-07 19:58:59 +08:00
|
|
|
|
// 信息补全
|
2025-10-10 20:26:17 +08:00
|
|
|
|
data.productId = product!.value.id;
|
|
|
|
|
|
data.productKey = product!.value.productKey;
|
|
|
|
|
|
fillExtraAttributes(data);
|
2025-10-13 10:17:19 +08:00
|
|
|
|
await (formType.value === 'create'
|
|
|
|
|
|
? createThingModel(data)
|
|
|
|
|
|
: updateThingModel(data));
|
|
|
|
|
|
message.success($t('ui.actionMessage.operationSuccess'));
|
2025-10-07 19:58:59 +08:00
|
|
|
|
// 关闭弹窗
|
2025-10-10 20:26:17 +08:00
|
|
|
|
dialogVisible.value = false;
|
|
|
|
|
|
emit('success');
|
2025-10-07 19:58:59 +08:00
|
|
|
|
} finally {
|
2025-10-10 20:26:17 +08:00
|
|
|
|
formLoading.value = false;
|
2025-10-07 19:58:59 +08:00
|
|
|
|
}
|
2025-10-13 10:17:19 +08:00
|
|
|
|
}
|
2025-10-07 19:58:59 +08:00
|
|
|
|
|
|
|
|
|
|
/** 填写额外的属性(处理不同类型的情况) */
|
2025-10-13 10:17:19 +08:00
|
|
|
|
function fillExtraAttributes(data: any) {
|
2025-10-07 19:58:59 +08:00
|
|
|
|
// 属性
|
|
|
|
|
|
if (data.type === IoTThingModelTypeEnum.PROPERTY) {
|
2025-10-10 20:26:17 +08:00
|
|
|
|
removeDataSpecs(data.property);
|
|
|
|
|
|
data.dataType = data.property.dataType;
|
|
|
|
|
|
data.property.identifier = data.identifier;
|
|
|
|
|
|
data.property.name = data.name;
|
|
|
|
|
|
delete data.service;
|
|
|
|
|
|
delete data.event;
|
2025-10-07 19:58:59 +08:00
|
|
|
|
}
|
|
|
|
|
|
// 服务
|
|
|
|
|
|
if (data.type === IoTThingModelTypeEnum.SERVICE) {
|
2025-10-10 20:26:17 +08:00
|
|
|
|
removeDataSpecs(data.service);
|
|
|
|
|
|
data.dataType = data.service.dataType;
|
|
|
|
|
|
data.service.identifier = data.identifier;
|
|
|
|
|
|
data.service.name = data.name;
|
|
|
|
|
|
delete data.property;
|
|
|
|
|
|
delete data.event;
|
2025-10-07 19:58:59 +08:00
|
|
|
|
}
|
|
|
|
|
|
// 事件
|
|
|
|
|
|
if (data.type === IoTThingModelTypeEnum.EVENT) {
|
2025-10-10 20:26:17 +08:00
|
|
|
|
removeDataSpecs(data.event);
|
|
|
|
|
|
data.dataType = data.event.dataType;
|
|
|
|
|
|
data.event.identifier = data.identifier;
|
|
|
|
|
|
data.event.name = data.name;
|
|
|
|
|
|
delete data.property;
|
|
|
|
|
|
delete data.service;
|
2025-10-07 19:58:59 +08:00
|
|
|
|
}
|
2025-10-13 10:17:19 +08:00
|
|
|
|
}
|
2025-10-07 19:58:59 +08:00
|
|
|
|
|
|
|
|
|
|
/** 处理 dataSpecs 为空的情况 */
|
2025-10-13 10:17:19 +08:00
|
|
|
|
function removeDataSpecs(val: any) {
|
2025-10-07 19:58:59 +08:00
|
|
|
|
if (!val.dataSpecs || Object.keys(val.dataSpecs).length === 0) {
|
2025-10-10 20:26:17 +08:00
|
|
|
|
delete val.dataSpecs;
|
2025-10-07 19:58:59 +08:00
|
|
|
|
}
|
|
|
|
|
|
if (!val.dataSpecsList || val.dataSpecsList.length === 0) {
|
2025-10-10 20:26:17 +08:00
|
|
|
|
delete val.dataSpecsList;
|
2025-10-07 19:58:59 +08:00
|
|
|
|
}
|
2025-10-13 10:17:19 +08:00
|
|
|
|
}
|
2025-10-07 19:58:59 +08:00
|
|
|
|
|
|
|
|
|
|
/** 重置表单 */
|
2025-10-13 10:17:19 +08:00
|
|
|
|
function resetForm() {
|
2025-10-07 19:58:59 +08:00
|
|
|
|
formData.value = {
|
2025-10-13 10:17:19 +08:00
|
|
|
|
type: IoTThingModelTypeEnum.PROPERTY.toString(),
|
2025-10-07 19:58:59 +08:00
|
|
|
|
dataType: IoTDataSpecsDataTypeEnum.INT,
|
|
|
|
|
|
property: {
|
|
|
|
|
|
dataType: IoTDataSpecsDataTypeEnum.INT,
|
|
|
|
|
|
dataSpecs: {
|
2025-10-10 20:26:17 +08:00
|
|
|
|
dataType: IoTDataSpecsDataTypeEnum.INT,
|
|
|
|
|
|
},
|
2025-10-07 19:58:59 +08:00
|
|
|
|
},
|
|
|
|
|
|
service: {},
|
2025-10-10 20:26:17 +08:00
|
|
|
|
event: {},
|
2025-10-13 10:17:19 +08:00
|
|
|
|
};
|
2025-10-10 20:26:17 +08:00
|
|
|
|
formRef.value?.resetFields();
|
2025-10-13 10:17:19 +08:00
|
|
|
|
}
|
2025-10-07 19:58:59 +08:00
|
|
|
|
</script>
|
2025-10-10 20:26:17 +08:00
|
|
|
|
|
|
|
|
|
|
<template>
|
|
|
|
|
|
<Dialog v-model="dialogVisible" :title="dialogTitle">
|
|
|
|
|
|
<a-form
|
|
|
|
|
|
ref="formRef"
|
|
|
|
|
|
:loading="formLoading"
|
|
|
|
|
|
:model="formData"
|
|
|
|
|
|
:rules="ThingModelFormRules"
|
|
|
|
|
|
:label-col="{ span: 6 }"
|
|
|
|
|
|
:wrapper-col="{ span: 18 }"
|
|
|
|
|
|
>
|
|
|
|
|
|
<a-form-item label="功能类型" name="type">
|
|
|
|
|
|
<a-radio-group v-model:value="formData.type">
|
|
|
|
|
|
<a-radio-button
|
2025-10-13 10:17:19 +08:00
|
|
|
|
v-for="dict in getDictOptions(
|
|
|
|
|
|
DICT_TYPE.IOT_THING_MODEL_TYPE,
|
|
|
|
|
|
'number',
|
|
|
|
|
|
)"
|
2025-10-10 20:26:17 +08:00
|
|
|
|
:key="dict.value"
|
|
|
|
|
|
:value="dict.value"
|
|
|
|
|
|
>
|
|
|
|
|
|
{{ dict.label }}
|
|
|
|
|
|
</a-radio-button>
|
|
|
|
|
|
</a-radio-group>
|
|
|
|
|
|
</a-form-item>
|
|
|
|
|
|
<a-form-item label="功能名称" name="name">
|
|
|
|
|
|
<a-input v-model:value="formData.name" placeholder="请输入功能名称" />
|
|
|
|
|
|
</a-form-item>
|
|
|
|
|
|
<a-form-item label="标识符" name="identifier">
|
|
|
|
|
|
<a-input
|
|
|
|
|
|
v-model:value="formData.identifier"
|
|
|
|
|
|
placeholder="请输入标识符"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</a-form-item>
|
|
|
|
|
|
<!-- 属性配置 -->
|
|
|
|
|
|
<ThingModelProperty
|
|
|
|
|
|
v-if="formData.type === IoTThingModelTypeEnum.PROPERTY"
|
|
|
|
|
|
v-model="formData.property"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<!-- 服务配置 -->
|
|
|
|
|
|
<ThingModelService
|
|
|
|
|
|
v-if="formData.type === IoTThingModelTypeEnum.SERVICE"
|
|
|
|
|
|
v-model="formData.service"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<!-- 事件配置 -->
|
|
|
|
|
|
<ThingModelEvent
|
|
|
|
|
|
v-if="formData.type === IoTThingModelTypeEnum.EVENT"
|
|
|
|
|
|
v-model="formData.event"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<a-form-item label="描述" name="description">
|
|
|
|
|
|
<a-textarea
|
|
|
|
|
|
v-model:value="formData.description"
|
|
|
|
|
|
:maxlength="200"
|
|
|
|
|
|
:rows="3"
|
|
|
|
|
|
placeholder="请输入属性描述"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</a-form-item>
|
|
|
|
|
|
</a-form>
|
|
|
|
|
|
|
|
|
|
|
|
<template #footer>
|
|
|
|
|
|
<a-button :disabled="formLoading" type="primary" @click="submitForm">
|
|
|
|
|
|
确 定
|
|
|
|
|
|
</a-button>
|
|
|
|
|
|
<a-button @click="dialogVisible = false">取 消</a-button>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</Dialog>
|
|
|
|
|
|
</template>
|