diff --git a/apps/web-antd/src/api/iot/device/device/index.ts b/apps/web-antd/src/api/iot/device/device/index.ts index 7bd59886f..a0d4659b0 100644 --- a/apps/web-antd/src/api/iot/device/device/index.ts +++ b/apps/web-antd/src/api/iot/device/device/index.ts @@ -77,14 +77,6 @@ export namespace IotDeviceApi { } } -/** IoT 设备状态枚举 */ -// TODO @haohao:packages/constants/src/biz-iot-enum.ts 枚举; -export enum DeviceStateEnum { - INACTIVE = 0, // 未激活 - OFFLINE = 2, // 离线 - ONLINE = 1, // 在线 -} - /** 查询设备分页 */ export function getDevicePage(params: PageParam) { return requestClient.get>( @@ -154,6 +146,14 @@ export function importDeviceTemplate() { return requestClient.download('/iot/device/get-import-template'); } +/** 导入设备 */ +export function importDevice(file: File, updateSupport: boolean) { + return requestClient.upload('/iot/device/import', { + file, + updateSupport, + }); +} + /** 获取设备属性最新数据 */ export function getLatestDeviceProperties(params: any) { return requestClient.get( diff --git a/apps/web-antd/src/api/iot/product/product/index.ts b/apps/web-antd/src/api/iot/product/product/index.ts index bf5682d2d..2833b1e5d 100644 --- a/apps/web-antd/src/api/iot/product/product/index.ts +++ b/apps/web-antd/src/api/iot/product/product/index.ts @@ -27,33 +27,6 @@ export namespace IotProductApi { } } -// TODO @haohao:packages/constants/src/biz-iot-enum.ts 枚举; - -/** IOT 产品设备类型枚举类 */ -export enum DeviceTypeEnum { - DEVICE = 0, // 直连设备 - GATEWAY = 2, // 网关设备 - GATEWAY_SUB = 1, // 网关子设备 -} - -/** IOT 产品定位类型枚举类 */ -export enum LocationTypeEnum { - IP = 1, // IP 定位 - MANUAL = 3, // 手动定位 - MODULE = 2, // 设备定位 -} - -/** IOT 数据格式(编解码器类型)枚举类 */ -export enum CodecTypeEnum { - ALINK = 'Alink', // 阿里云 Alink 协议 -} - -/** IOT 产品状态枚举类 */ -export enum ProductStatusEnum { - UNPUBLISHED = 0, // 开发中 - PUBLISHED = 1, // 已发布 -} - /** 查询产品分页 */ export function getProductPage(params: PageParam) { return requestClient.get>( diff --git a/apps/web-antd/src/views/iot/device/device/data.ts b/apps/web-antd/src/views/iot/device/device/data.ts index 5edd1cc0d..3c2bfc694 100644 --- a/apps/web-antd/src/views/iot/device/device/data.ts +++ b/apps/web-antd/src/views/iot/device/device/data.ts @@ -7,10 +7,9 @@ import { getDictOptions } from '@vben/hooks'; import { z } from '#/adapter/form'; import { getSimpleDeviceList } from '#/api/iot/device/device'; import { getSimpleDeviceGroupList } from '#/api/iot/device/group'; -import { - DeviceTypeEnum, - getSimpleProductList, -} from '#/api/iot/product/product'; +import { DeviceTypeEnum } from '@vben/constants'; + +import { getSimpleProductList } from '#/api/iot/product/product'; /** 新增/修改的表单 */ export function useFormSchema(): VbenFormSchema[] { @@ -33,6 +32,10 @@ export function useFormSchema(): VbenFormSchema[] { valueField: 'id', placeholder: '请选择产品', }, + dependencies: { + triggerFields: ['id'], + disabled: (values: any) => !!values?.id, + }, rules: 'required', }, { @@ -42,6 +45,10 @@ export function useFormSchema(): VbenFormSchema[] { componentProps: { placeholder: '请输入 DeviceName', }, + dependencies: { + triggerFields: ['id'], + disabled: (values: any) => !!values?.id, + }, rules: z .string() .min(4, 'DeviceName 长度不能少于 4 个字符') diff --git a/apps/web-antd/src/views/iot/device/device/index.vue b/apps/web-antd/src/views/iot/device/device/index.vue index 83c391aa4..153099e79 100644 --- a/apps/web-antd/src/views/iot/device/device/index.vue +++ b/apps/web-antd/src/views/iot/device/device/index.vue @@ -1,5 +1,6 @@ + + + + diff --git a/apps/web-antd/src/views/iot/device/device/modules/components/device-table-select.vue b/apps/web-antd/src/views/iot/device/device/modules/components/device-table-select.vue deleted file mode 100644 index 8f8afc3e0..000000000 --- a/apps/web-antd/src/views/iot/device/device/modules/components/device-table-select.vue +++ /dev/null @@ -1,402 +0,0 @@ - - - - diff --git a/apps/web-antd/src/views/iot/device/device/modules/detail/index.vue b/apps/web-antd/src/views/iot/device/device/modules/detail/index.vue index d8bf6a095..0f7929684 100644 --- a/apps/web-antd/src/views/iot/device/device/modules/detail/index.vue +++ b/apps/web-antd/src/views/iot/device/device/modules/detail/index.vue @@ -10,17 +10,19 @@ import { Page } from '@vben/common-ui'; import { message, Tabs } from 'ant-design-vue'; +import { DeviceTypeEnum } from '@vben/constants'; + import { getDevice } from '#/api/iot/device/device'; -import { DeviceTypeEnum, getProduct } from '#/api/iot/product/product'; +import { getProduct } from '#/api/iot/product/product'; import { getThingModelListByProductId } from '#/api/iot/thingmodel'; -import DeviceDetailConfig from './device-detail-config.vue'; -import DeviceDetailsHeader from './device-details-header.vue'; -import DeviceDetailsInfo from './device-details-info.vue'; -import DeviceDetailsMessage from './device-details-message.vue'; -import DeviceDetailsSimulator from './device-details-simulator.vue'; -import DeviceDetailsSubDevice from './device-details-sub-device.vue'; -import DeviceDetailsThingModel from './device-details-thing-model.vue'; +import DeviceDetailConfig from './modules/config.vue'; +import DeviceDetailsHeader from './modules/header.vue'; +import DeviceDetailsInfo from './modules/info.vue'; +import DeviceDetailsMessage from './modules/message.vue'; +import DeviceDetailsSimulator from './modules/simulator.vue'; +import DeviceDetailsSubDevice from './modules/sub-device.vue'; +import DeviceDetailsThingModel from './modules/thing-model.vue'; defineOptions({ name: 'IoTDeviceDetail' }); @@ -52,8 +54,8 @@ async function getDeviceData(deviceId: number) { async function getProductData(productId: number) { try { product.value = await getProduct(productId); - } catch (error) { - console.error('获取产品详情失败:', error); + } catch { + message.error('获取产品详情失败'); } } @@ -62,8 +64,8 @@ async function getThingModelList(productId: number) { try { const data = await getThingModelListByProductId(productId); thingModelList.value = data || []; - } catch (error) { - console.error('获取物模型列表失败:', error); + } catch { + message.error('获取物模型列表失败'); thingModelList.value = []; } } diff --git a/apps/web-antd/src/views/iot/device/device/modules/detail/device-detail-config.vue b/apps/web-antd/src/views/iot/device/device/modules/detail/modules/config.vue similarity index 100% rename from apps/web-antd/src/views/iot/device/device/modules/detail/device-detail-config.vue rename to apps/web-antd/src/views/iot/device/device/modules/detail/modules/config.vue diff --git a/apps/web-antd/src/views/iot/device/device/modules/detail/device-details-header.vue b/apps/web-antd/src/views/iot/device/device/modules/detail/modules/header.vue similarity index 76% rename from apps/web-antd/src/views/iot/device/device/modules/detail/device-details-header.vue rename to apps/web-antd/src/views/iot/device/device/modules/detail/modules/header.vue index d0de74904..493d2ed76 100644 --- a/apps/web-antd/src/views/iot/device/device/modules/detail/device-details-header.vue +++ b/apps/web-antd/src/views/iot/device/device/modules/detail/modules/header.vue @@ -1,14 +1,14 @@ - - diff --git a/apps/web-antd/src/views/iot/device/device/modules/detail/device-details-info.vue b/apps/web-antd/src/views/iot/device/device/modules/detail/modules/info.vue similarity index 80% rename from apps/web-antd/src/views/iot/device/device/modules/detail/device-details-info.vue rename to apps/web-antd/src/views/iot/device/device/modules/detail/modules/info.vue index fc7f056ea..a1b5f6406 100644 --- a/apps/web-antd/src/views/iot/device/device/modules/detail/device-details-info.vue +++ b/apps/web-antd/src/views/iot/device/device/modules/detail/modules/info.vue @@ -1,5 +1,4 @@ - - - - - - diff --git a/apps/web-antd/src/views/iot/device/device/modules/device-import-form.vue b/apps/web-antd/src/views/iot/device/device/modules/device-import-form.vue deleted file mode 100644 index 710971ce1..000000000 --- a/apps/web-antd/src/views/iot/device/device/modules/device-import-form.vue +++ /dev/null @@ -1,133 +0,0 @@ - - - diff --git a/apps/web-antd/src/views/iot/device/device/modules/device-form.vue b/apps/web-antd/src/views/iot/device/device/modules/form.vue similarity index 73% rename from apps/web-antd/src/views/iot/device/device/modules/device-form.vue rename to apps/web-antd/src/views/iot/device/device/modules/form.vue index 39fe16a99..2994e8d00 100644 --- a/apps/web-antd/src/views/iot/device/device/modules/device-form.vue +++ b/apps/web-antd/src/views/iot/device/device/modules/form.vue @@ -3,11 +3,16 @@ import type { IotDeviceApi } from '#/api/iot/device/device'; import { computed, ref } from 'vue'; -import { useVbenForm, useVbenModal } from '@vben/common-ui'; +import { useVbenModal } from '@vben/common-ui'; import { message } from 'ant-design-vue'; -import { createDevice, getDevice, updateDevice } from '#/api/iot/device/device'; +import { useVbenForm } from '#/adapter/form'; +import { + createDevice, + getDevice, + updateDevice, +} from '#/api/iot/device/device'; import { $t } from '#/locales'; import { useFormSchema } from '../data'; @@ -15,9 +20,11 @@ import { useFormSchema } from '../data'; defineOptions({ name: 'IoTDeviceForm' }); const emit = defineEmits(['success']); -const formData = ref(); +const formData = ref(); const getTitle = computed(() => { - return formData.value?.id ? '编辑设备' : '新增设备'; + return formData.value?.id + ? $t('ui.actionTitle.edit', ['设备']) + : $t('ui.actionTitle.create', ['设备']); }); const [Form, formApi] = useVbenForm({ @@ -33,6 +40,7 @@ const [Form, formApi] = useVbenForm({ }); const [Modal, modalApi] = useVbenModal({ + /** 提交表单 */ async onConfirm() { const { valid } = await formApi.validate(); if (!valid) { @@ -43,7 +51,6 @@ const [Modal, modalApi] = useVbenModal({ const data = (await formApi.getValues()) as IotDeviceApi.Device; try { await (formData.value?.id ? updateDevice(data) : createDevice(data)); - // 关闭并提示 await modalApi.close(); emit('success'); message.success($t('ui.actionMessage.operationSuccess')); @@ -51,20 +58,23 @@ const [Modal, modalApi] = useVbenModal({ modalApi.unlock(); } }, + /** 弹窗打开/关闭 */ async onOpenChange(isOpen: boolean) { if (!isOpen) { formData.value = undefined; return; } // 加载数据 - const data = modalApi.getData(); + const data = modalApi.getData(); if (!data || !data.id) { + // 新增模式:设置默认值(如果需要) + formData.value = undefined; return; } + // 编辑模式:加载数据 modalApi.lock(); try { formData.value = await getDevice(data.id); - // 设置到 values await formApi.setValues(formData.value); } finally { modalApi.unlock(); diff --git a/apps/web-antd/src/views/iot/device/device/modules/device-group-form.vue b/apps/web-antd/src/views/iot/device/device/modules/group-form.vue similarity index 91% rename from apps/web-antd/src/views/iot/device/device/modules/device-group-form.vue rename to apps/web-antd/src/views/iot/device/device/modules/group-form.vue index fa85a0ffb..86b37032a 100644 --- a/apps/web-antd/src/views/iot/device/device/modules/device-group-form.vue +++ b/apps/web-antd/src/views/iot/device/device/modules/group-form.vue @@ -1,10 +1,11 @@ + + diff --git a/apps/web-antd/src/views/iot/product/product/index.vue b/apps/web-antd/src/views/iot/product/product/index.vue index 3aa14191d..421514c36 100644 --- a/apps/web-antd/src/views/iot/product/product/index.vue +++ b/apps/web-antd/src/views/iot/product/product/index.vue @@ -12,6 +12,8 @@ import { downloadFileFromBlobPart } from '@vben/utils'; import { Button, Card, Input, message, Space } from 'ant-design-vue'; +import { ProductStatusEnum } from '@vben/constants'; + import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; import { getSimpleProductCategoryList } from '#/api/iot/product/category'; import { @@ -253,6 +255,7 @@ onMounted(() => { type: 'link', danger: true, icon: ACTION_ICON.DELETE, + disabled: row.status === ProductStatusEnum.PUBLISHED, popConfirm: { title: `确认删除产品 ${row.name} 吗?`, confirm: handleDelete.bind(null, row), diff --git a/apps/web-antd/src/views/iot/product/product/modules/detail/modules/header.vue b/apps/web-antd/src/views/iot/product/product/modules/detail/modules/header.vue index ef31b79de..62df0cae1 100644 --- a/apps/web-antd/src/views/iot/product/product/modules/detail/modules/header.vue +++ b/apps/web-antd/src/views/iot/product/product/modules/detail/modules/header.vue @@ -7,10 +7,9 @@ import { useVbenModal } from '@vben/common-ui'; import { Button, Card, Descriptions, message, Modal } from 'ant-design-vue'; -import { - ProductStatusEnum, - updateProductStatus, -} from '#/api/iot/product/product'; +import { ProductStatusEnum } from '@vben/constants'; + +import { updateProductStatus } from '#/api/iot/product/product'; import Form from '../../form.vue'; diff --git a/apps/web-antd/src/views/iot/product/product/modules/detail/modules/info.vue b/apps/web-antd/src/views/iot/product/product/modules/detail/modules/info.vue index 2693fff49..3d0ae5b99 100644 --- a/apps/web-antd/src/views/iot/product/product/modules/detail/modules/info.vue +++ b/apps/web-antd/src/views/iot/product/product/modules/detail/modules/info.vue @@ -5,7 +5,7 @@ import { DICT_TYPE } from '@vben/constants'; import { Card, Descriptions } from 'ant-design-vue'; -import { DeviceTypeEnum } from '#/api/iot/product/product'; +import { DeviceTypeEnum } from '@vben/constants'; import { DictTag } from '#/components/dict-tag'; interface Props { diff --git a/packages/constants/src/biz-iot-enum.ts b/packages/constants/src/biz-iot-enum.ts index ad2f3bd5a..f494a9a78 100644 --- a/packages/constants/src/biz-iot-enum.ts +++ b/packages/constants/src/biz-iot-enum.ts @@ -1 +1,43 @@ -// TODO @haohao:枚举可以放到这里; +// ========== IOT - 设备模块 ========== +/** + * 设备状态枚举 + */ +export const DeviceStateEnum = { + INACTIVE: 0, // 未激活 + OFFLINE: 2, // 离线 + ONLINE: 1, // 在线 +} as const; + +// ========== IOT - 产品模块 ========== +/** + * 产品设备类型枚举 + */ +export const DeviceTypeEnum = { + DEVICE: 0, // 直连设备 + GATEWAY: 2, // 网关设备 + GATEWAY_SUB: 1, // 网关子设备 +} as const; + +/** + * 产品状态枚举 + */ +export const ProductStatusEnum = { + UNPUBLISHED: 0, // 开发中 + PUBLISHED: 1, // 已发布 +} as const; + +/** + * 产品定位类型枚举 + */ +export const LocationTypeEnum = { + IP: 1, // IP 定位 + MANUAL: 3, // 手动定位 + MODULE: 2, // 设备定位 +} as const; + +/** + * 数据格式(编解码器类型)枚举 + */ +export const CodecTypeEnum = { + ALINK: 'Alink', // 阿里云 Alink 协议 +} as const;