From 250d3eb39f5f437c4ae9d5a18d7312fc9bd79c54 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 20 May 2026 09:57:47 +0800 Subject: [PATCH] =?UTF-8?q?feat=EF=BC=88iot=EF=BC=89:=20=E8=BF=81=E7=A7=BB?= =?UTF-8?q?=20iot=20=E5=9C=A8=20ele=20=E7=9A=84=20api?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web-ele/src/api/iot/alert/config/index.ts | 57 +++++ .../web-ele/src/api/iot/alert/record/index.ts | 45 ++++ .../src/api/iot/device/device/index.ts | 231 +++++++++++++++++ .../web-ele/src/api/iot/device/group/index.ts | 51 ++++ .../src/api/iot/device/modbus/config/index.ts | 30 +++ .../src/api/iot/device/modbus/point/index.ts | 52 ++++ .../web-ele/src/api/iot/ota/firmware/index.ts | 50 ++++ apps/web-ele/src/api/iot/ota/task/index.ts | 42 +++ .../src/api/iot/ota/task/record/index.ts | 46 ++++ .../src/api/iot/product/category/index.ts | 56 ++++ .../src/api/iot/product/product/index.ts | 111 ++++++++ .../src/api/iot/rule/data/rule/index.ts | 44 ++++ .../src/api/iot/rule/data/sink/index.ts | 176 +++++++++++++ apps/web-ele/src/api/iot/rule/scene/index.ts | 151 +++++++++++ apps/web-ele/src/api/iot/statistics/index.ts | 49 ++++ apps/web-ele/src/api/iot/thingmodel/index.ts | 242 ++++++++++++++++++ 16 files changed, 1433 insertions(+) create mode 100644 apps/web-ele/src/api/iot/alert/config/index.ts create mode 100644 apps/web-ele/src/api/iot/alert/record/index.ts create mode 100644 apps/web-ele/src/api/iot/device/device/index.ts create mode 100644 apps/web-ele/src/api/iot/device/group/index.ts create mode 100644 apps/web-ele/src/api/iot/device/modbus/config/index.ts create mode 100644 apps/web-ele/src/api/iot/device/modbus/point/index.ts create mode 100644 apps/web-ele/src/api/iot/ota/firmware/index.ts create mode 100644 apps/web-ele/src/api/iot/ota/task/index.ts create mode 100644 apps/web-ele/src/api/iot/ota/task/record/index.ts create mode 100644 apps/web-ele/src/api/iot/product/category/index.ts create mode 100644 apps/web-ele/src/api/iot/product/product/index.ts create mode 100644 apps/web-ele/src/api/iot/rule/data/rule/index.ts create mode 100644 apps/web-ele/src/api/iot/rule/data/sink/index.ts create mode 100644 apps/web-ele/src/api/iot/rule/scene/index.ts create mode 100644 apps/web-ele/src/api/iot/statistics/index.ts create mode 100644 apps/web-ele/src/api/iot/thingmodel/index.ts diff --git a/apps/web-ele/src/api/iot/alert/config/index.ts b/apps/web-ele/src/api/iot/alert/config/index.ts new file mode 100644 index 000000000..ac41c67c2 --- /dev/null +++ b/apps/web-ele/src/api/iot/alert/config/index.ts @@ -0,0 +1,57 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace AlertConfigApi { + /** IoT 告警配置 */ + export interface AlertConfig { + id?: number; + name?: string; + description?: string; + level?: number; + status?: number; + sceneRuleIds?: number[]; + receiveUserIds?: number[]; + receiveUserNames?: string[]; + receiveTypes?: number[]; + createTime?: Date; + updateTime?: Date; + } +} + +/** 查询告警配置分页 */ +export function getAlertConfigPage(params: PageParam) { + return requestClient.get>( + '/iot/alert-config/page', + { params }, + ); +} + +/** 查询告警配置详情 */ +export function getAlertConfig(id: number) { + return requestClient.get( + `/iot/alert-config/get?id=${id}`, + ); +} + +/** 获取告警配置简单列表 */ +export function getSimpleAlertConfigList() { + return requestClient.get( + '/iot/alert-config/simple-list', + ); +} + +/** 新增告警配置 */ +export function createAlertConfig(data: AlertConfigApi.AlertConfig) { + return requestClient.post('/iot/alert-config/create', data); +} + +/** 修改告警配置 */ +export function updateAlertConfig(data: AlertConfigApi.AlertConfig) { + return requestClient.put('/iot/alert-config/update', data); +} + +/** 删除告警配置 */ +export function deleteAlertConfig(id: number) { + return requestClient.delete(`/iot/alert-config/delete?id=${id}`); +} diff --git a/apps/web-ele/src/api/iot/alert/record/index.ts b/apps/web-ele/src/api/iot/alert/record/index.ts new file mode 100644 index 000000000..d0292d4d4 --- /dev/null +++ b/apps/web-ele/src/api/iot/alert/record/index.ts @@ -0,0 +1,45 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace AlertRecordApi { + /** IoT 告警记录 */ + export interface AlertRecord { + id?: number; + configId?: number; + configName?: string; + configLevel?: number; + deviceId?: number; + deviceName?: string; + productId?: number; + productName?: string; + deviceMessage?: any; + processStatus?: boolean; + processRemark?: string; + processTime?: Date; + createTime?: Date; + } +} + +/** 查询告警记录分页 */ +export function getAlertRecordPage(params: PageParam) { + return requestClient.get>( + '/iot/alert-record/page', + { params }, + ); +} + +/** 查询告警记录详情 */ +export function getAlertRecord(id: number) { + return requestClient.get( + `/iot/alert-record/get?id=${id}`, + ); +} + +/** 处理告警记录 */ +export function processAlertRecord(id: number, processRemark?: string) { + return requestClient.put('/iot/alert-record/process', { + id, + processRemark, + }); +} diff --git a/apps/web-ele/src/api/iot/device/device/index.ts b/apps/web-ele/src/api/iot/device/device/index.ts new file mode 100644 index 000000000..a55b017d5 --- /dev/null +++ b/apps/web-ele/src/api/iot/device/device/index.ts @@ -0,0 +1,231 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace IotDeviceApi { + /** 设备 */ + export interface Device { + id?: number; // 设备编号 + deviceName: string; // 设备名称 + nickname?: string; // 备注名称 + serialNumber?: string; // 设备序列号 + picUrl?: string; // 设备图片 + groupIds?: number[]; // 设备分组编号数组 + productId: number; // 产品编号 + productKey?: string; // 产品标识 + productName?: string; // 产品名称(只有部分接口返回,例如 getDeviceLocationList) + deviceType?: number; // 设备类型 + gatewayId?: number; // 网关设备 ID + state?: number; // 设备状态 + onlineTime?: Date; // 最后上线时间 + offlineTime?: Date; // 最后离线时间 + activeTime?: Date; // 设备激活时间 + deviceSecret?: string; // 设备密钥,用于设备认证 + config?: string; // 设备配置 + latitude?: number; // 设备位置的纬度 + longitude?: number; // 设备位置的经度 + createTime?: Date; // 创建时间 + } + + /** 设备更新分组 Request VO */ + export interface DeviceUpdateGroupReqVO { + ids: number[]; // 设备编号列表(必填) + groupIds: number[]; // 分组编号列表(必填) + } + + /** 设备认证信息 Response VO */ + export interface DeviceAuthInfoRespVO { + clientId: string; // 客户端 ID + username: string; // 用户名 + password: string; // 密码 + } + + /** 设备导入 Response VO */ + export interface DeviceImportRespVO { + createDeviceNames?: string[]; // 创建成功的设备名称列表 + updateDeviceNames?: string[]; // 更新成功的设备名称列表 + failureDeviceNames?: Record; // 失败的设备名称及原因 + } + + /** IoT 设备属性详细 VO */ + export interface DevicePropertyDetail { + identifier: string; // 属性标识符 + value: string; // 最新值 + updateTime: Date; // 更新时间 + name: string; // 属性名称 + dataType: string; // 数据类型 + dataSpecs: any; // 数据定义 + dataSpecsList: any[]; // 数据定义列表 + } + + /** 设备属性 VO */ + export interface DeviceProperty { + identifier: string; // 属性标识符 + value: string; // 最新值 + updateTime: Date; // 更新时间 + } + + /** 设备发送消息 Request VO */ + export interface DeviceMessageSendReq { + deviceId: number; // 设备编号 + method: string; // 请求方法 + params?: any; // 请求参数 + } +} + +/** 查询设备分页 */ +export function getDevicePage(params: PageParam) { + return requestClient.get>( + '/iot/device/page', + { params }, + ); +} + +/** 查询设备详情 */ +export function getDevice(id: number) { + return requestClient.get(`/iot/device/get?id=${id}`); +} + +/** 新增设备 */ +export function createDevice(data: IotDeviceApi.Device) { + return requestClient.post('/iot/device/create', data); +} + +/** 修改设备 */ +export function updateDevice(data: IotDeviceApi.Device) { + return requestClient.put('/iot/device/update', data); +} + +/** 修改设备分组 */ +export function updateDeviceGroup(data: IotDeviceApi.DeviceUpdateGroupReqVO) { + return requestClient.put('/iot/device/update-group', data); +} + +/** 删除单个设备 */ +export function deleteDevice(id: number) { + return requestClient.delete(`/iot/device/delete?id=${id}`); +} + +/** 删除多个设备 */ +export function deleteDeviceList(ids: number[]) { + return requestClient.delete('/iot/device/delete-list', { + params: { ids: ids.join(',') }, + }); +} + +/** 导出设备 */ +export function exportDeviceExcel(params: PageParam) { + return requestClient.download('/iot/device/export-excel', { params }); +} + +/** 获取设备数量 */ +export function getDeviceCount(productId: number) { + return requestClient.get(`/iot/device/count?productId=${productId}`); +} + +/** 获取设备的精简信息列表 */ +export function getSimpleDeviceList(deviceType?: number, productId?: number) { + return requestClient.get('/iot/device/simple-list', { + params: { deviceType, productId }, + }); +} + +/** 根据产品编号,获取设备的精简信息列表 */ +export function getDeviceListByProductId(productId: number) { + return requestClient.get('/iot/device/simple-list', { + params: { productId }, + }); +} + +/** 获取设备位置列表(用于地图展示) */ +export function getDeviceLocationList() { + return requestClient.get('/iot/device/location-list'); +} + +/** 获取导入模板 */ +export function importDeviceTemplate() { + return requestClient.download('/iot/device/get-import-template'); +} + +/** 导入设备 */ +export function importDevice(file: File, updateSupport: boolean) { + return requestClient.upload( + `/iot/device/import?updateSupport=${updateSupport}`, + { file }, + ); +} + +/** 获取设备属性最新数据 */ +export function getLatestDeviceProperties(params: any) { + return requestClient.get( + '/iot/device/property/get-latest', + { params }, + ); +} + +/** 获取设备属性历史数据 */ +export function getHistoryDevicePropertyList(params: any) { + return requestClient.get( + '/iot/device/property/history-list', + { params }, + ); +} + +/** 获取设备认证信息 */ +export function getDeviceAuthInfo(id: number) { + return requestClient.get( + '/iot/device/get-auth-info', + { params: { id } }, + ); +} + +/** 查询设备消息分页 */ +export function getDeviceMessagePage(params: PageParam) { + return requestClient.get>('/iot/device/message/page', { + params, + }); +} + +/** 查询设备消息配对分页 */ +export function getDeviceMessagePairPage(params: PageParam) { + return requestClient.get>('/iot/device/message/pair-page', { + params, + }); +} + +/** 发送设备消息 */ +export function sendDeviceMessage(params: IotDeviceApi.DeviceMessageSendReq) { + return requestClient.post('/iot/device/message/send', params); +} + +/** 绑定子设备到网关设备 */ +export function bindDeviceGateway(gatewayId: number, subIds: number[]) { + return requestClient.put('/iot/device/bind-gateway', { + gatewayId, + subIds, + }); +} + +/** 解绑子设备与网关设备 */ +export function unbindDeviceGateway(gatewayId: number, subIds: number[]) { + return requestClient.put('/iot/device/unbind-gateway', { + gatewayId, + subIds, + }); +} + +/** 获取网关设备的子设备列表 */ +export function getSubDeviceList(gatewayId: number) { + return requestClient.get( + '/iot/device/sub-device-list', + { params: { gatewayId } }, + ); +} + +/** 获取未绑定的子设备分页 */ +export function getUnboundSubDevicePage(params: PageParam) { + return requestClient.get>( + '/iot/device/unbound-sub-device-page', + { params }, + ); +} diff --git a/apps/web-ele/src/api/iot/device/group/index.ts b/apps/web-ele/src/api/iot/device/group/index.ts new file mode 100644 index 000000000..2c11411ae --- /dev/null +++ b/apps/web-ele/src/api/iot/device/group/index.ts @@ -0,0 +1,51 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace IotDeviceGroupApi { + /** 设备分组 */ + export interface DeviceGroup { + id?: number; // 分组 ID + name: string; // 分组名字 + status?: number; // 分组状态 + description?: string; // 分组描述 + deviceCount?: number; // 设备数量 + } +} + +/** 查询设备分组分页 */ +export function getDeviceGroupPage(params: PageParam) { + return requestClient.get>( + '/iot/device-group/page', + { params }, + ); +} + +/** 查询设备分组详情 */ +export function getDeviceGroup(id: number) { + return requestClient.get( + `/iot/device-group/get?id=${id}`, + ); +} + +/** 新增设备分组 */ +export function createDeviceGroup(data: IotDeviceGroupApi.DeviceGroup) { + return requestClient.post('/iot/device-group/create', data); +} + +/** 修改设备分组 */ +export function updateDeviceGroup(data: IotDeviceGroupApi.DeviceGroup) { + return requestClient.put('/iot/device-group/update', data); +} + +/** 删除设备分组 */ +export function deleteDeviceGroup(id: number) { + return requestClient.delete(`/iot/device-group/delete?id=${id}`); +} + +/** 获取设备分组的精简信息列表 */ +export function getSimpleDeviceGroupList() { + return requestClient.get( + '/iot/device-group/simple-list', + ); +} diff --git a/apps/web-ele/src/api/iot/device/modbus/config/index.ts b/apps/web-ele/src/api/iot/device/modbus/config/index.ts new file mode 100644 index 000000000..3ee1e4f10 --- /dev/null +++ b/apps/web-ele/src/api/iot/device/modbus/config/index.ts @@ -0,0 +1,30 @@ +import { requestClient } from '#/api/request'; + +export namespace IotDeviceModbusConfigApi { + /** Modbus 连接配置 VO */ + export interface ModbusConfig { + id?: number; // 主键 + deviceId: number; // 设备编号 + ip: string; // Modbus 服务器 IP 地址 + port: number; // Modbus 服务器端口 + slaveId: number; // 从站地址 + timeout: number; // 连接超时时间,单位:毫秒 + retryInterval: number; // 重试间隔,单位:毫秒 + mode: number; // 模式 + frameFormat: number; // 帧格式 + status: number; // 状态 + } +} + +/** 获取设备的 Modbus 连接配置 */ +export function getModbusConfig(deviceId: number) { + return requestClient.get( + '/iot/device-modbus-config/get', + { params: { deviceId } }, + ); +} + +/** 保存 Modbus 连接配置 */ +export function saveModbusConfig(data: IotDeviceModbusConfigApi.ModbusConfig) { + return requestClient.post('/iot/device-modbus-config/save', data); +} diff --git a/apps/web-ele/src/api/iot/device/modbus/point/index.ts b/apps/web-ele/src/api/iot/device/modbus/point/index.ts new file mode 100644 index 000000000..11b440fae --- /dev/null +++ b/apps/web-ele/src/api/iot/device/modbus/point/index.ts @@ -0,0 +1,52 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace IotDeviceModbusPointApi { + /** Modbus 点位配置 VO */ + export interface ModbusPoint { + id?: number; // 主键 + deviceId: number; // 设备编号 + thingModelId?: number; // 物模型属性编号 + identifier: string; // 属性标识符 + name: string; // 属性名称 + functionCode?: number; // Modbus 功能码 + registerAddress?: number; // 寄存器起始地址 + registerCount?: number; // 寄存器数量 + byteOrder?: string; // 字节序 + rawDataType?: string; // 原始数据类型 + scale: number; // 缩放因子 + pollInterval: number; // 轮询间隔,单位:毫秒 + status: number; // 状态 + } +} + +/** 获取设备的 Modbus 点位分页 */ +export function getModbusPointPage(params: PageParam) { + return requestClient.get>( + '/iot/device-modbus-point/page', + { params }, + ); +} + +/** 获取 Modbus 点位详情 */ +export function getModbusPoint(id: number) { + return requestClient.get( + `/iot/device-modbus-point/get?id=${id}`, + ); +} + +/** 创建 Modbus 点位配置 */ +export function createModbusPoint(data: IotDeviceModbusPointApi.ModbusPoint) { + return requestClient.post('/iot/device-modbus-point/create', data); +} + +/** 更新 Modbus 点位配置 */ +export function updateModbusPoint(data: IotDeviceModbusPointApi.ModbusPoint) { + return requestClient.put('/iot/device-modbus-point/update', data); +} + +/** 删除 Modbus 点位配置 */ +export function deleteModbusPoint(id: number) { + return requestClient.delete(`/iot/device-modbus-point/delete?id=${id}`); +} diff --git a/apps/web-ele/src/api/iot/ota/firmware/index.ts b/apps/web-ele/src/api/iot/ota/firmware/index.ts new file mode 100644 index 000000000..7fd7469ca --- /dev/null +++ b/apps/web-ele/src/api/iot/ota/firmware/index.ts @@ -0,0 +1,50 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace IoTOtaFirmwareApi { + /** IoT OTA 固件信息 */ + export interface Firmware { + id?: number; + name?: string; + description?: string; + version?: string; + productId?: number; + productName?: string; + fileUrl?: string; + fileSize?: number; + fileDigestAlgorithm?: string; + fileDigestValue?: string; + createTime?: Date; + } +} + +/** 查询 OTA 固件分页 */ +export function getOtaFirmwarePage(params: PageParam) { + return requestClient.get>( + '/iot/ota/firmware/page', + { params }, + ); +} + +/** 查询 OTA 固件详情 */ +export function getOtaFirmware(id: number) { + return requestClient.get( + `/iot/ota/firmware/get?id=${id}`, + ); +} + +/** 新增 OTA 固件 */ +export function createOtaFirmware(data: IoTOtaFirmwareApi.Firmware) { + return requestClient.post('/iot/ota/firmware/create', data); +} + +/** 修改 OTA 固件 */ +export function updateOtaFirmware(data: IoTOtaFirmwareApi.Firmware) { + return requestClient.put('/iot/ota/firmware/update', data); +} + +/** 删除 OTA 固件 */ +export function deleteOtaFirmware(id: number) { + return requestClient.delete(`/iot/ota/firmware/delete?id=${id}`); +} diff --git a/apps/web-ele/src/api/iot/ota/task/index.ts b/apps/web-ele/src/api/iot/ota/task/index.ts new file mode 100644 index 000000000..7f4f5d6fb --- /dev/null +++ b/apps/web-ele/src/api/iot/ota/task/index.ts @@ -0,0 +1,42 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace IoTOtaTaskApi { + /** IoT OTA 升级任务 */ + export interface Task { + id?: number; + name?: string; + description?: string; + firmwareId?: number; + status?: number; + deviceScope?: number; + deviceIds?: number[]; + deviceTotalCount?: number; + deviceSuccessCount?: number; + createTime?: Date; + } +} + +/** 查询 OTA 升级任务分页 */ +export function getOtaTaskPage(params: PageParam) { + return requestClient.get>( + '/iot/ota/task/page', + { params }, + ); +} + +/** 查询 OTA 升级任务详情 */ +export function getOtaTask(id: number) { + return requestClient.get(`/iot/ota/task/get?id=${id}`); +} + +/** 新增 OTA 升级任务 */ +export function createOtaTask(data: IoTOtaTaskApi.Task) { + return requestClient.post('/iot/ota/task/create', data); +} + +/** 取消 OTA 升级任务 */ +export function cancelOtaTask(id: number) { + return requestClient.post(`/iot/ota/task/cancel?id=${id}`); +} diff --git a/apps/web-ele/src/api/iot/ota/task/record/index.ts b/apps/web-ele/src/api/iot/ota/task/record/index.ts new file mode 100644 index 000000000..29eada8b6 --- /dev/null +++ b/apps/web-ele/src/api/iot/ota/task/record/index.ts @@ -0,0 +1,46 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace IoTOtaTaskRecordApi { + /** IoT OTA 升级任务记录 */ + export interface TaskRecord { + id?: number; + firmwareId?: number; + firmwareVersion?: string; + taskId?: number; + deviceId?: string; + deviceName?: string; + currentVersion?: string; + fromFirmwareId?: number; + fromFirmwareVersion?: string; + status?: number; + progress?: number; + description?: string; + updateTime?: Date; + } +} + +/** 查询 OTA 升级任务记录分页 */ +export function getOtaTaskRecordPage(params: PageParam) { + return requestClient.get>( + '/iot/ota/task/record/page', + { params }, + ); +} + +/** 取消 OTA 升级任务记录 */ +export function cancelOtaTaskRecord(id: number) { + return requestClient.put(`/iot/ota/task/record/cancel?id=${id}`); +} + +/** 获取 OTA 升级任务记录状态统计 */ +export function getOtaTaskRecordStatusStatistics( + firmwareId?: number, + taskId?: number, +) { + return requestClient.get>( + '/iot/ota/task/record/get-status-statistics', + { params: { firmwareId, taskId } }, + ); +} diff --git a/apps/web-ele/src/api/iot/product/category/index.ts b/apps/web-ele/src/api/iot/product/category/index.ts new file mode 100644 index 000000000..45ce4ccdb --- /dev/null +++ b/apps/web-ele/src/api/iot/product/category/index.ts @@ -0,0 +1,56 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace IotProductCategoryApi { + /** 产品分类 */ + export interface ProductCategory { + id?: number; // 分类 ID + name: string; // 分类名称 + sort?: number; // 分类排序 + status?: number; // 分类状态 + description?: string; // 分类描述 + createTime?: Date; // 创建时间 + } +} + +/** 查询产品分类分页 */ +export function getProductCategoryPage(params: PageParam) { + return requestClient.get>( + '/iot/product-category/page', + { params }, + ); +} + +/** 查询产品分类详情 */ +export function getProductCategory(id: number) { + return requestClient.get( + `/iot/product-category/get?id=${id}`, + ); +} + +/** 新增产品分类 */ +export function createProductCategory( + data: IotProductCategoryApi.ProductCategory, +) { + return requestClient.post('/iot/product-category/create', data); +} + +/** 修改产品分类 */ +export function updateProductCategory( + data: IotProductCategoryApi.ProductCategory, +) { + return requestClient.put('/iot/product-category/update', data); +} + +/** 刪除产品分类 */ +export function deleteProductCategory(id: number) { + return requestClient.delete(`/iot/product-category/delete?id=${id}`); +} + +/** 获取产品分类精简列表 */ +export function getSimpleProductCategoryList() { + return requestClient.get( + '/iot/product-category/simple-list', + ); +} diff --git a/apps/web-ele/src/api/iot/product/product/index.ts b/apps/web-ele/src/api/iot/product/product/index.ts new file mode 100644 index 000000000..9d0bb3515 --- /dev/null +++ b/apps/web-ele/src/api/iot/product/product/index.ts @@ -0,0 +1,111 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace IotProductApi { + /** 产品 */ + export interface Product { + id?: number; // 产品编号 + name: string; // 产品名称 + productKey?: string; // 产品标识 + productSecret?: string; // 产品密钥 + protocolId?: number; // 协议编号 + protocolType?: string; // 协议类型 + categoryId?: number; // 产品所属品类标识符 + categoryName?: string; // 产品所属品类名称 + icon?: string; // 产品图标 + picUrl?: string; // 产品图片 + description?: string; // 产品描述 + status?: number; // 产品状态 + deviceType?: number; // 设备类型 + netType?: number; // 联网方式 + serializeType?: string; // 序列化类型 + registerEnabled?: boolean; // 是否开启动态注册 + deviceCount?: number; // 设备数量 + createTime?: Date; // 创建时间 + } +} + +// IoT 协议类型枚举 +export enum ProtocolTypeEnum { + COAP = 'coap', + EMQX = 'emqx', + HTTP = 'http', + MODBUS_TCP_CLIENT = 'modbus_tcp_client', + MODBUS_TCP_SERVER = 'modbus_tcp_server', + MQTT = 'mqtt', + TCP = 'tcp', + UDP = 'udp', + WEBSOCKET = 'websocket', +} + +// IoT 序列化类型枚举 +export enum SerializeTypeEnum { + BINARY = 'binary', + JSON = 'json', +} + +/** 查询产品分页 */ +export function getProductPage(params: PageParam) { + return requestClient.get>( + '/iot/product/page', + { params }, + ); +} + +/** 查询产品详情 */ +export function getProduct(id: number) { + return requestClient.get(`/iot/product/get?id=${id}`); +} + +/** 新增产品 */ +export function createProduct(data: IotProductApi.Product) { + return requestClient.post('/iot/product/create', data); +} + +/** 修改产品 */ +export function updateProduct(data: IotProductApi.Product) { + return requestClient.put('/iot/product/update', data); +} + +/** 删除产品 */ +export function deleteProduct(id: number) { + return requestClient.delete(`/iot/product/delete?id=${id}`); +} + +/** 导出产品 Excel */ +export function exportProduct(params: any) { + return requestClient.download('/iot/product/export-excel', { params }); +} + +/** 更新产品状态 */ +export function updateProductStatus(id: number, status: number) { + return requestClient.put( + `/iot/product/update-status?id=${id}&status=${status}`, + ); +} + +/** 查询产品(精简)列表 */ +export function getSimpleProductList(deviceType?: number) { + return requestClient.get( + '/iot/product/simple-list', + { + params: { deviceType }, + }, + ); +} + +/** 根据 ProductKey 获取产品信息 */ +export function getProductByKey(productKey: string) { + return requestClient.get('/iot/product/get-by-key', { + params: { productKey }, + }); +} + +// TODO @AI:这个是不是 vue3 + ep 也没做?感觉对齐就好,不用额外做。 +/** 同步产品物模型 TDengine 超级表结构 */ +export function syncProductPropertyTable(productId: number) { + return requestClient.post( + `/iot/product/sync-property-table?productId=${productId}`, + ); +} diff --git a/apps/web-ele/src/api/iot/rule/data/rule/index.ts b/apps/web-ele/src/api/iot/rule/data/rule/index.ts new file mode 100644 index 000000000..e9ba120b2 --- /dev/null +++ b/apps/web-ele/src/api/iot/rule/data/rule/index.ts @@ -0,0 +1,44 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace DataRuleApi { + /** IoT 数据流转规则 */ + export interface DataRule { + id?: number; + name?: string; + description?: string; + status?: number; + sourceConfigs?: any[]; + sinkIds?: number[]; + createTime?: Date; + } +} + +/** 查询数据流转规则分页 */ +export function getDataRulePage(params: PageParam) { + return requestClient.get>( + '/iot/data-rule/page', + { params }, + ); +} + +/** 查询数据流转规则详情 */ +export function getDataRule(id: number) { + return requestClient.get(`/iot/data-rule/get?id=${id}`); +} + +/** 新增数据流转规则 */ +export function createDataRule(data: DataRuleApi.DataRule) { + return requestClient.post('/iot/data-rule/create', data); +} + +/** 修改数据流转规则 */ +export function updateDataRule(data: DataRuleApi.DataRule) { + return requestClient.put('/iot/data-rule/update', data); +} + +/** 删除数据流转规则 */ +export function deleteDataRule(id: number) { + return requestClient.delete(`/iot/data-rule/delete?id=${id}`); +} diff --git a/apps/web-ele/src/api/iot/rule/data/sink/index.ts b/apps/web-ele/src/api/iot/rule/data/sink/index.ts new file mode 100644 index 000000000..c4d1429ce --- /dev/null +++ b/apps/web-ele/src/api/iot/rule/data/sink/index.ts @@ -0,0 +1,176 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +interface BaseConfig { + type: string; +} + +export namespace DataSinkApi { + /** IoT 数据流转目的 VO */ + export interface DataSink { + id?: number; + name?: string; + description?: string; + status?: number; + direction?: number; + type?: number; + config?: + | DatabaseConfig + | HttpConfig + | KafkaMQConfig + | MqttConfig + | RabbitMQConfig + | RedisStreamMQConfig + | RocketMQConfig + | TcpConfig + | WebSocketConfig; + createTime?: Date; + } + + /** HTTP 配置 */ + export interface HttpConfig extends BaseConfig { + url: string; + method: string; + headers: Record; + query: Record; + body: string; + } + + /** TCP 配置 */ + export interface TcpConfig extends BaseConfig { + host: string; + port: number; + connectTimeoutMs: number; + readTimeoutMs: number; + ssl: boolean; + sslCertPath: string; + dataFormat: string; + heartbeatIntervalMs: number; + reconnectIntervalMs: number; + maxReconnectAttempts: number; + } + + /** WebSocket 配置 */ + export interface WebSocketConfig extends BaseConfig { + serverUrl: string; + connectTimeoutMs: number; + sendTimeoutMs: number; + heartbeatIntervalMs: number; + heartbeatMessage: string; + subprotocols: string; + customHeaders: string; + verifySslCert: boolean; + dataFormat: string; + reconnectIntervalMs: number; + maxReconnectAttempts: number; + enableCompression: boolean; + sendRetryCount: number; + sendRetryIntervalMs: number; + } + + /** MQTT 配置 */ + export interface MqttConfig extends BaseConfig { + url: string; + username: string; + password: string; + clientId: string; + topic: string; + } + + /** Database 配置 */ + export interface DatabaseConfig extends BaseConfig { + jdbcUrl: string; + username: string; + password: string; + tableName: string; + } + + /** RocketMQ 配置 */ + export interface RocketMQConfig extends BaseConfig { + nameServer: string; + accessKey: string; + secretKey: string; + group: string; + topic: string; + tags: string; + } + + /** Kafka 配置 */ + export interface KafkaMQConfig extends BaseConfig { + bootstrapServers: string; + username: string; + password: string; + ssl: boolean; + topic: string; + } + + /** RabbitMQ 配置 */ + export interface RabbitMQConfig extends BaseConfig { + host: string; + port: number; + virtualHost: string; + username: string; + password: string; + exchange: string; + routingKey: string; + queue: string; + } + + /** Redis Stream MQ 配置 */ + export interface RedisStreamMQConfig extends BaseConfig { + host: string; + port: number; + password: string; + database: number; + topic: string; + } +} + +/** 数据流转目的类型 */ +export const IotDataSinkTypeEnum = { + HTTP: 1, + TCP: 2, + WEBSOCKET: 3, + MQTT: 10, + DATABASE: 20, + REDIS_STREAM: 21, + ROCKETMQ: 30, + RABBITMQ: 31, + KAFKA: 32, +} as const; + +/** 查询数据流转目的分页 */ +export function getDataSinkPage(params: PageParam) { + return requestClient.get>( + '/iot/data-sink/page', + { params }, + ); +} + +/** 查询数据流转目的详情 */ +export function getDataSink(id: number) { + return requestClient.get( + `/iot/data-sink/get?id=${id}`, + ); +} + +/** 查询数据流转目的(精简)列表 */ +export function getDataSinkSimpleList() { + return requestClient.get('/iot/data-sink/simple-list'); +} + +/** 新增数据流转目的 */ +export function createDataSink(data: DataSinkApi.DataSink) { + return requestClient.post('/iot/data-sink/create', data); +} + +/** 修改数据流转目的 */ +export function updateDataSink(data: DataSinkApi.DataSink) { + return requestClient.put('/iot/data-sink/update', data); +} + +/** 删除数据流转目的 */ +export function deleteDataSink(id: number) { + return requestClient.delete(`/iot/data-sink/delete?id=${id}`); +} diff --git a/apps/web-ele/src/api/iot/rule/scene/index.ts b/apps/web-ele/src/api/iot/rule/scene/index.ts new file mode 100644 index 000000000..a449af69c --- /dev/null +++ b/apps/web-ele/src/api/iot/rule/scene/index.ts @@ -0,0 +1,151 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace RuleSceneApi { + /** 场景联动规则 */ + export interface SceneRule { + id?: number; + name: string; + description?: string; + status?: number; + triggers?: Trigger[]; + actions?: Action[]; + createTime?: Date; + } + + /** 场景联动规则的触发器 */ + export interface Trigger { + type?: number; + productId?: number; + deviceId?: number; + identifier?: string; + operator?: string; + value?: any; + cronExpression?: string; + // 后端结构:List>;外层「或」、组内「且」 + conditionGroups?: TriggerCondition[][]; + } + + /** 场景联动规则的触发条件 */ + export interface TriggerCondition { + productId?: number; + deviceId?: number; + identifier?: string; + operator?: string; + value?: any; + type?: number; + param?: string; + } + + /** 场景联动规则的动作 */ + export interface Action { + type?: number; + productId?: number; + deviceId?: number; + identifier?: string; + value?: any; + alertConfigId?: number; + params?: Record; + } +} + +// TODO @haohao:貌似下面的,和 RuleSceneApi 重复了。 +/** IoT 场景联动规则 */ +export interface IotSceneRule { + id?: number; + name?: string; + description?: string; + status?: number; + triggers?: Trigger[]; + actions?: Action[]; + createTime?: Date; +} + +/** IoT 场景联动规则触发器 */ +export interface Trigger { + type?: number; + productId?: number; + deviceId?: number; + identifier?: string; + operator?: string; + value?: any; + cronExpression?: string; + // 后端结构:List>;外层「或」、组内「且」 + conditionGroups?: TriggerCondition[][]; +} + +/** IoT 场景联动规则触发条件 */ +export interface TriggerCondition { + productId?: number; + deviceId?: number; + identifier?: string; + operator?: string; + value?: any; + type?: number; + param?: string; +} + +/** IoT 场景联动规则动作 */ +export interface Action { + type?: number; + productId?: number; + deviceId?: number; + identifier?: string; + value?: any; + alertConfigId?: number; + params?: Record; +} + +/** 查询场景联动规则分页 */ +export function getSceneRulePage(params: PageParam) { + return requestClient.get>( + '/iot/scene-rule/page', + { params }, + ); +} + +/** 查询场景联动规则详情 */ +export function getSceneRule(id: number) { + return requestClient.get( + `/iot/scene-rule/get?id=${id}`, + ); +} + +/** 新增场景联动规则 */ +export function createSceneRule(data: IotSceneRule) { + return requestClient.post('/iot/scene-rule/create', data); +} + +/** 修改场景联动规则 */ +export function updateSceneRule(data: IotSceneRule) { + return requestClient.put('/iot/scene-rule/update', data); +} + +/** 删除场景联动规则 */ +export function deleteSceneRule(id: number) { + return requestClient.delete(`/iot/scene-rule/delete?id=${id}`); +} + +/** 批量删除场景联动规则 */ +// TODO @haohao:貌似用上。 +export function deleteSceneRuleList(ids: number[]) { + return requestClient.delete('/iot/scene-rule/delete-list', { + params: { ids: ids.join(',') }, + }); +} + +/** 更新场景联动规则状态 */ +export function updateSceneRuleStatus(id: number, status: number) { + return requestClient.put(`/iot/scene-rule/update-status`, { + id, + status, + }); +} + +/** 获取场景联动规则简单列表 */ +export function getSimpleRuleSceneList() { + return requestClient.get( + '/iot/scene-rule/simple-list', + ); +} diff --git a/apps/web-ele/src/api/iot/statistics/index.ts b/apps/web-ele/src/api/iot/statistics/index.ts new file mode 100644 index 000000000..dc7971eb6 --- /dev/null +++ b/apps/web-ele/src/api/iot/statistics/index.ts @@ -0,0 +1,49 @@ +import { requestClient } from '#/api/request'; + +export namespace IotStatisticsApi { + /** 统计摘要数据 */ + export interface StatisticsSummaryRespVO { + productCategoryCount: number; // 品类数量 + productCount: number; // 产品数量 + deviceCount: number; // 设备数量 + deviceMessageCount: number; // 上报数量 + productCategoryTodayCount: number; // 今日新增品类数量 + productTodayCount: number; // 今日新增产品数量 + deviceTodayCount: number; // 今日新增设备数量 + deviceMessageTodayCount: number; // 今日新增上报数量 + deviceOnlineCount: number; // 在线数量 + deviceOfflineCount: number; // 离线数量 + deviceInactiveCount: number; // 待激活设备数量 + productCategoryDeviceCounts: Record; // 按品类统计的设备数量 + } + + /** 设备消息数量统计(按日期) */ + export interface DeviceMessageSummaryByDateRespVO { + time: string; // 时间轴 + upstreamCount: number; // 上行消息数量 + downstreamCount: number; // 下行消息数量 + } + + /** 设备消息统计请求 */ + export interface DeviceMessageReqVO { + interval: number; + times?: string[]; + } +} + +/** 获取 IoT 统计摘要数据 */ +export function getStatisticsSummary() { + return requestClient.get( + '/iot/statistics/get-summary', + ); +} + +/** 获取设备消息的数据统计(按日期) */ +export function getDeviceMessageSummaryByDate( + params: IotStatisticsApi.DeviceMessageReqVO, +) { + return requestClient.get( + '/iot/statistics/get-device-message-summary-by-date', + { params }, + ); +} diff --git a/apps/web-ele/src/api/iot/thingmodel/index.ts b/apps/web-ele/src/api/iot/thingmodel/index.ts new file mode 100644 index 000000000..66fa208cf --- /dev/null +++ b/apps/web-ele/src/api/iot/thingmodel/index.ts @@ -0,0 +1,242 @@ +import type { FormItemRule } from 'element-plus'; + +import type { PageParam, PageResult } from '@vben/request'; + +import { isEmpty } from '@vben/utils'; + +import { requestClient } from '#/api/request'; + +export namespace ThingModelApi { + /** IoT 物模型数据 */ + export interface ThingModel { + id?: number; + productId?: number; + productKey?: string; + identifier?: string; + name?: string; + description?: string; + dataType?: string; + type?: number; // 参见 IoTThingModelTypeEnum 枚举类 + property?: Property; + event?: Event; + service?: Service; + } + + /** IoT 物模型属性 */ + export interface Property { + identifier?: string; + name?: string; + accessMode?: string; + required?: boolean; + dataType?: string; + description?: string; + dataSpecs?: any; + dataSpecsList?: any[]; + } + + /** IoT 物模型服务 */ + export interface Service { + identifier?: string; + name?: string; + required?: boolean; + callType?: string; + description?: string; + inputParams?: Param[]; + outputParams?: Param[]; + method?: string; + } + + /** IoT 物模型事件 */ + export interface Event { + identifier?: string; + name?: string; + required?: boolean; + type?: string; + description?: string; + outputParams?: Param[]; + method?: string; + } + + /** IoT 物模型参数 */ + export interface Param { + identifier?: string; + name?: string; + direction?: string; + paraOrder?: number; + dataType?: string; + dataSpecs?: any; + dataSpecsList?: any[]; + } + + /** IoT 数据定义(数值型) */ + export interface DataSpecsNumberData { + min?: number | string; + max?: number | string; + step?: number | string; + unit?: string; + unitName?: string; + } + + /** IoT 数据定义(枚举/布尔型) */ + export interface DataSpecsEnumOrBoolData { + value: number | string; + name: string; + } +} + +/** 生成「必填 + 数字」类校验器:拼到 size / length / 枚举值上 */ +function buildRequiredNumberValidator(label: string) { + return (_rule: any, value: any, callback: any) => { + if (isEmpty(value)) { + callback(new Error(`${label}不能为空`)); + return; + } + if (Number.isNaN(Number(value))) { + callback(new Error(`${label}必须是数字`)); + return; + } + callback(); + }; +} + +/** 生成「标识符样式」名称校验器:开头需为中文 / 英文 / 数字,整体仅允许中文、英文、数字、下划线、短划线,长度 ≤ 20 */ +export function buildIdentifierLikeNameValidator(label: string) { + return (_rule: any, value: string, callback: any) => { + if (isEmpty(value)) { + callback(new Error(`${label}不能为空`)); + return; + } + if (!/^[一-龥A-Za-z0-9]/.test(value)) { + callback(new Error(`${label}必须以中文、英文字母或数字开头`)); + return; + } + if (!/^[一-龥A-Za-z0-9][\w一-龥-]*$/.test(value)) { + callback( + new Error(`${label}只能包含中文、英文字母、数字、下划线和短划线`), + ); + return; + } + if (value.length > 20) { + callback(new Error(`${label}长度不能超过 20 个字符`)); + return; + } + callback(); + }; +} + +/** IoT 物模型表单校验规则 */ +export const ThingModelFormRules: Record = { + name: [ + { required: true, message: '功能名称不能为空', trigger: 'blur' }, + { + pattern: /^[一-龥A-Za-z0-9][一-龥A-Za-z0-9\-_/.]{0,29}$/, + message: + '支持中文、大小写字母、日文、数字、短划线、下划线、斜杠和小数点,必须以中文、英文或数字开头,不超过 30 个字符', + trigger: 'blur', + }, + ], + type: [{ required: true, message: '功能类型不能为空', trigger: 'blur' }], + identifier: [ + { required: true, message: '标识符不能为空', trigger: 'blur' }, + { + pattern: /^\w{1,50}$/, + message: '支持大小写字母、数字和下划线,不超过 50 个字符', + trigger: 'blur', + }, + { + validator: (_rule: any, value: string, callback: any) => { + const reservedKeywords = [ + 'set', + 'get', + 'post', + 'property', + 'event', + 'time', + 'value', + ]; + if (reservedKeywords.includes(value)) { + callback( + new Error( + 'set, get, post, property, event, time, value 是系统保留字段,不能用于标识符定义', + ), + ); + return; + } + if (/^\d+$/.test(value)) { + callback(new Error('标识符不能是纯数字')); + return; + } + callback(); + }, + trigger: 'blur', + }, + ], + childDataType: [{ required: true, message: '元素类型不能为空' }], + size: [ + { + required: true, + validator: buildRequiredNumberValidator('元素个数'), + trigger: 'blur', + }, + ], + length: [ + { + required: true, + validator: buildRequiredNumberValidator('文本长度'), + trigger: 'blur', + }, + ], + accessMode: [{ required: true, message: '请选择读写类型', trigger: 'change' }], + callType: [{ required: true, message: '请选择调用方式', trigger: 'change' }], + eventType: [{ required: true, message: '请选择事件类型', trigger: 'change' }], +}; + +/** 校验布尔值名称 */ +export const validateBoolName = buildIdentifierLikeNameValidator('布尔值名称'); + +/** 查询产品物模型分页 */ +export function getThingModelPage(params: PageParam) { + return requestClient.get>( + '/iot/thing-model/page', + { params }, + ); +} + +/** 查询产品物模型详情 */ +export function getThingModel(id: number) { + return requestClient.get( + `/iot/thing-model/get?id=${id}`, + ); +} + +/** 根据产品 ID 查询物模型列表 */ +export function getThingModelListByProductId(productId: number) { + return requestClient.get( + '/iot/thing-model/list', + { + params: { productId }, + }, + ); +} + +/** 新增物模型 */ +export function createThingModel(data: ThingModelApi.ThingModel) { + return requestClient.post('/iot/thing-model/create', data); +} + +/** 修改物模型 */ +export function updateThingModel(data: ThingModelApi.ThingModel) { + return requestClient.put('/iot/thing-model/update', data); +} + +/** 删除物模型 */ +export function deleteThingModel(id: number) { + return requestClient.delete(`/iot/thing-model/delete?id=${id}`); +} + +/** 获取物模型 TSL */ +export function getThingModelTSL(productId: number) { + return requestClient.get('/iot/thing-model/get-tsl', { + params: { productId }, + }); +}