diff --git a/apps/web-antd/public/images/device/device-card.png b/apps/web-antd/public/images/device/device-card.png new file mode 100644 index 0000000..2eedfa2 Binary files /dev/null and b/apps/web-antd/public/images/device/device-card.png differ diff --git a/apps/web-antd/public/images/device/device-type-1.png b/apps/web-antd/public/images/device/device-type-1.png new file mode 100644 index 0000000..44f89c8 Binary files /dev/null and b/apps/web-antd/public/images/device/device-type-1.png differ diff --git a/apps/web-antd/public/images/device/device-type-2.png b/apps/web-antd/public/images/device/device-type-2.png new file mode 100644 index 0000000..201579d Binary files /dev/null and b/apps/web-antd/public/images/device/device-type-2.png differ diff --git a/apps/web-antd/public/images/device/device-type-3.png b/apps/web-antd/public/images/device/device-type-3.png new file mode 100644 index 0000000..3561237 Binary files /dev/null and b/apps/web-antd/public/images/device/device-type-3.png differ diff --git a/apps/web-antd/src/api/device/product/index.ts b/apps/web-antd/src/api/device/product/index.ts new file mode 100644 index 0000000..542cbee --- /dev/null +++ b/apps/web-antd/src/api/device/product/index.ts @@ -0,0 +1,61 @@ +import type { ProductVO, ProductForm, ProductQuery } from './model'; + +import type { ID, IDS } from '#/api/common'; +import type { PageResult } from '#/api/common'; + +import { commonExport } from '#/api/helper'; +import { requestClient } from '#/api/request'; + +/** +* 查询设备产品列表 +* @param params +* @returns 设备产品列表 +*/ +export function productList(params?: ProductQuery) { + return requestClient.get>('/device/product/list', { params }); +} + +/** + * 导出设备产品列表 + * @param params + * @returns 设备产品列表 + */ +export function productExport(params?: ProductQuery) { + return commonExport('/device/product/export', params ?? {}); +} + +/** + * 查询设备产品详情 + * @param id id + * @returns 设备产品详情 + */ +export function productInfo(id: ID) { + return requestClient.get(`/device/product/${id}`); +} + +/** + * 新增设备产品 + * @param data + * @returns void + */ +export function productAdd(data: ProductForm) { + return requestClient.postWithMsg('/device/product', data); +} + +/** + * 更新设备产品 + * @param data + * @returns void + */ +export function productUpdate(data: ProductForm) { + return requestClient.putWithMsg('/device/product', data); +} + +/** + * 删除设备产品 + * @param id id + * @returns void + */ +export function productRemove(id: ID | IDS) { + return requestClient.deleteWithMsg(`/device/product/${id}`); +} diff --git a/apps/web-antd/src/api/device/product/model.d.ts b/apps/web-antd/src/api/device/product/model.d.ts new file mode 100644 index 0000000..6b27107 --- /dev/null +++ b/apps/web-antd/src/api/device/product/model.d.ts @@ -0,0 +1,204 @@ +import type { PageQuery, BaseEntity } from '#/api/common'; + +export interface ProductVO { + /** + * 编号 + */ + id: string | number; + + /** + * 产品名称 + */ + productName: string; + + /** + * 产品图片 + */ + imgId: string | number; + + /** + * 描述 + */ + description: string; + + /** + * 分类id + */ + categoryId: string | number; + + /** + * 协议id + */ + protocolId: string | number; + + /** + * 物模型 + */ + metadata: string; + + /** + * 设备类型 + */ + deviceType: string; + + /** + * 协议配置 + */ + protocolConf: string; + + /** + * 启用状态 0 禁用 + */ + enabled: string; + + /** + * 接入方式 + */ + provider: string | number; + + /** + * 存储策略 + */ + storePolicy: string; + + /** + * 存储策略配置 + */ + storePolicyConf: string; + +} + +export interface ProductForm extends BaseEntity { + /** + * 编号 + */ + id?: string | number; + + /** + * 产品名称 + */ + productName?: string; + + /** + * 产品图片 + */ + imgId?: string | number; + + /** + * 描述 + */ + description?: string; + + /** + * 分类id + */ + categoryId?: string | number; + + /** + * 协议id + */ + protocolId?: string | number; + + /** + * 物模型 + */ + metadata?: string; + + /** + * 设备类型 + */ + deviceType?: string; + + /** + * 协议配置 + */ + protocolConf?: string; + + /** + * 启用状态 0 禁用 + */ + enabled?: string; + + /** + * 接入方式 + */ + provider?: string | number; + + /** + * 存储策略 + */ + storePolicy?: string; + + /** + * 存储策略配置 + */ + storePolicyConf?: string; + +} + +export interface ProductQuery extends PageQuery { + /** + * 产品名称 + */ + productName?: string; + + /** + * 产品图片 + */ + imgId?: string | number; + + /** + * 描述 + */ + description?: string; + + /** + * 分类id + */ + categoryId?: string | number; + + /** + * 协议id + */ + protocolId?: string | number; + + /** + * 物模型 + */ + metadata?: string; + + /** + * 设备类型 + */ + deviceType?: string; + + /** + * 协议配置 + */ + protocolConf?: string; + + /** + * 启用状态 0 禁用 + */ + enabled?: string; + + /** + * 接入方式 + */ + provider?: string | number; + + /** + * 存储策略 + */ + storePolicy?: string; + + /** + * 存储策略配置 + */ + storePolicyConf?: string; + + /** + * 日期范围参数 + */ + params?: any; +} diff --git a/apps/web-antd/src/api/device/productCategory/index.ts b/apps/web-antd/src/api/device/productCategory/index.ts index 11e1319..b02c432 100644 --- a/apps/web-antd/src/api/device/productCategory/index.ts +++ b/apps/web-antd/src/api/device/productCategory/index.ts @@ -20,6 +20,18 @@ export function productCategoryList(params?: ProductCategoryQuery) { ); } +/** + * 查询产品分类列表 + * @param params + * @returns 产品分类列表 + */ +export function productCategoryTreeList(params?: ProductCategoryQuery) { + return requestClient.get( + `/device/productCategory/treeList`, + { params }, + ); +} + /** * 查询产品分类详情 * @param id id diff --git a/apps/web-antd/src/constants/dicts/device.ts b/apps/web-antd/src/constants/dicts/device.ts new file mode 100644 index 0000000..07cf9dd --- /dev/null +++ b/apps/web-antd/src/constants/dicts/device.ts @@ -0,0 +1,23 @@ +/* 运维字典 */ + +// 网络类型 +export const deviceTypeOptions = [ + { + label: '直连设备', + value: 'device', + iconUrl: './device/device-type-1.png', + tooltip: '直连物联网平台的设备', + }, + { + label: '网关子设备', + value: 'childrenDevice', + iconUrl: './device/device-type-2.png', + tooltip: '作为网关的子设备,由网关代理连接到物联网平台', + }, + { + label: '网关设备', + value: 'gateway', + iconUrl: './device/device-type-3.png', + tooltip: '能挂载子设备与平台进行通信的设备', + }, +]; diff --git a/apps/web-antd/src/constants/dicts/index.ts b/apps/web-antd/src/constants/dicts/index.ts index 4a20a4d..095224f 100644 --- a/apps/web-antd/src/constants/dicts/index.ts +++ b/apps/web-antd/src/constants/dicts/index.ts @@ -1,4 +1,6 @@ /* 本地字典 */ + +export * from './device'; export * from './operations'; // 启用状态 diff --git a/apps/web-antd/src/views/operations/user.data.ts b/apps/web-antd/src/constants/dicts/operations.ts similarity index 88% rename from apps/web-antd/src/views/operations/user.data.ts rename to apps/web-antd/src/constants/dicts/operations.ts index 5eb3d62..98f5b94 100644 --- a/apps/web-antd/src/views/operations/user.data.ts +++ b/apps/web-antd/src/constants/dicts/operations.ts @@ -1,3 +1,6 @@ +/* 运维字典 */ + +// 网络类型 export const networkTypeOptions = [ { label: 'MQTT客户端', @@ -16,7 +19,3 @@ export const networkTypeOptions = [ 'HTTP服务是一个简单的请求-响应的基于TCP的无状态协议。设备通过HTTP服务与平台进行灵活的短链接通信,仅支持设备和平台之间单对单的请求-响应模式', }, ]; -export const enabledOptions = [ - { label: '启用', value: '1' }, - { label: '禁用', value: '0' }, -]; diff --git a/apps/web-antd/src/router/access.ts b/apps/web-antd/src/router/access.ts index 5d2bd4b..aea6399 100644 --- a/apps/web-antd/src/router/access.ts +++ b/apps/web-antd/src/router/access.ts @@ -31,7 +31,6 @@ const routeMetaMapping: Record> = { activePath: '/system/role', requireHomeRedirect: true, }, - '/system/oss-config/index': { activePath: '/system/oss', requireHomeRedirect: true, diff --git a/apps/web-antd/src/views/device/product/data.ts b/apps/web-antd/src/views/device/product/data.ts new file mode 100644 index 0000000..271da7b --- /dev/null +++ b/apps/web-antd/src/views/device/product/data.ts @@ -0,0 +1,158 @@ +import type { FormSchemaGetter } from '#/adapter/form'; +import type { VxeGridProps } from '#/adapter/vxe-table'; + +import { h } from 'vue'; + +import { deviceTypeOptions, enabledOptions } from '#/constants/dicts'; + +export const querySchema: FormSchemaGetter = () => [ + { + component: 'Input', + fieldName: 'productName', + label: '产品名称', + }, + { + component: 'TreeSelect', + fieldName: 'categoryId', + componentProps: { + fieldNames: { children: 'children', label: 'label', value: 'id' }, + }, + label: '产品分类', + }, + { + component: 'Select', + componentProps: { + options: deviceTypeOptions, + }, + fieldName: 'deviceType', + label: '设备类型', + }, + { + component: 'Select', + componentProps: { + options: enabledOptions, + }, + fieldName: 'enabled', + label: '启用状态', + }, +]; + +// 需要使用i18n注意这里要改成getter形式 否则切换语言不会刷新 +// export const columns: () => VxeGridProps['columns'] = () => [ +export const columns: VxeGridProps['columns'] = [ + { type: 'checkbox', width: 60 }, + // { + // title: '编号', + // field: 'id', + // }, + { + title: '产品编码', + field: 'productKey', + }, + { + title: '产品名称', + field: 'productName', + }, + { + title: '设备类型', + field: 'deviceType', + }, + { + title: '启用状态', + field: 'enabled', + slots: { default: 'enabled' }, + }, + { + title: '描述', + field: 'description', + }, + { + field: 'action', + fixed: 'right', + slots: { default: 'action' }, + title: '操作', + width: 180, + }, +]; + +export const drawerSchema: FormSchemaGetter = () => [ + { + label: '编号', + fieldName: 'id', + component: 'Input', + dependencies: { + show: () => false, + triggerFields: [''], + }, + }, + { + label: '产品编码', + fieldName: 'productKey', + component: 'Input', + }, + { + label: '产品名称', + fieldName: 'productName', + component: 'Input', + rules: 'required', + }, + { + label: '产品图片', + fieldName: 'imgId', + component: 'ImageUpload', + componentProps: { + // accept: 'image/*', // 可选拓展名或者mime类型 ,拼接 + // maxCount: 1, // 最大上传文件数 默认为1 为1会绑定为string而非string[]类型 + }, + }, + { + component: 'TreeSelect', + fieldName: 'categoryId', + componentProps: { + fieldNames: { children: 'children', label: 'label', value: 'id' }, + }, + label: '产品分类', + }, + { + label: '设备类型', + fieldName: 'deviceType', + component: 'Select', + componentProps: { + options: deviceTypeOptions, + }, + rules: 'selectRequired', + renderComponentContent: () => { + return { + option: (option: any) => { + return h('div', { class: 'flex flex-col', title: option.tooltip }, [ + h('span', { class: 'font-medium text-blue-500' }, option.label), + h( + 'span', + { + class: 'text-[14px] text-black/25 truncate', + style: + 'max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;', + }, + option.tooltip, + ), + ]); + }, + }; + }, + }, + { + label: '描述', + fieldName: 'description', + component: 'Textarea', + }, + { + label: '启用状态', + fieldName: 'enabled', + component: 'Input', + defaultValue: '0', + dependencies: { + show: () => false, + triggerFields: [''], + }, + }, +]; diff --git a/apps/web-antd/src/views/device/product/index.vue b/apps/web-antd/src/views/device/product/index.vue new file mode 100644 index 0000000..ec3d1b5 --- /dev/null +++ b/apps/web-antd/src/views/device/product/index.vue @@ -0,0 +1,220 @@ + + + diff --git a/apps/web-antd/src/views/device/product/product-drawer.vue b/apps/web-antd/src/views/device/product/product-drawer.vue new file mode 100644 index 0000000..a8d76b8 --- /dev/null +++ b/apps/web-antd/src/views/device/product/product-drawer.vue @@ -0,0 +1,123 @@ + + +