diff --git a/apps/web-antd/src/views/iot/product/product/data.ts b/apps/web-antd/src/views/iot/product/product/data.ts index 68fd51b46e98c868a13e7eb9add4c76e7faf365b..8811e2c64f1614365267eead4d709615dfe4d253 100644 --- a/apps/web-antd/src/views/iot/product/product/data.ts +++ b/apps/web-antd/src/views/iot/product/product/data.ts @@ -1,17 +1,19 @@ import type { VbenFormSchema } from '#/adapter/form'; import type { VxeTableGridOptions } from '#/adapter/vxe-table'; -import { ref } from 'vue'; +import { h, ref } from 'vue'; import { DICT_TYPE } from '@vben/constants'; import { getDictOptions } from '@vben/hooks'; +import { Button } from 'ant-design-vue'; + import { z } from '#/adapter/form'; import { getSimpleProductCategoryList } from '#/api/iot/product/category'; import { getProductPage } from '#/api/iot/product/product'; /** 新增/修改产品的表单 */ -export function useFormSchema(): VbenFormSchema[] { +export function useFormSchema(formApi?: any): VbenFormSchema[] { return [ { component: 'Input', @@ -21,6 +23,55 @@ export function useFormSchema(): VbenFormSchema[] { show: () => false, }, }, + // 创建时的 ProductKey 字段(带生成按钮) + { + fieldName: 'productKey', + label: 'ProductKey', + component: 'Input', + componentProps: { + placeholder: '请输入 ProductKey', + }, + dependencies: { + triggerFields: ['id'], + if(values) { + // 仅在创建时显示(没有 id) + return !values.id; + }, + }, + rules: z + .string() + .min(1, 'ProductKey 不能为空') + .max(32, 'ProductKey 长度不能超过 32 个字符'), + suffix: () => { + return h(Button, { + type: 'default', + onClick: () => { + formApi?.setFieldValue('productKey', generateProductKey()); + }, + }, { default: () => '重新生成' }); + }, + }, + // 编辑时的 ProductKey 字段(禁用,无按钮) + { + fieldName: 'productKey', + label: 'ProductKey', + component: 'Input', + componentProps: { + placeholder: '请输入 ProductKey', + disabled: true, + }, + dependencies: { + triggerFields: ['id'], + if(values) { + // 仅在编辑时显示(有 id) + return !!values.id; + }, + }, + rules: z + .string() + .min(1, 'ProductKey 不能为空') + .max(32, 'ProductKey 长度不能超过 32 个字符'), + }, { fieldName: 'name', label: '产品名称', @@ -67,26 +118,37 @@ export function useFormSchema(): VbenFormSchema[] { rules: 'required', }, { - fieldName: 'protocolType', - label: '接入协议', - component: 'Select', + fieldName: 'codecType', + label: '数据格式', + component: 'RadioGroup', componentProps: { - options: getDictOptions(DICT_TYPE.IOT_PROTOCOL_TYPE, 'number'), - placeholder: '请选择接入协议', + options: getDictOptions(DICT_TYPE.IOT_CODEC_TYPE, 'string'), + buttonStyle: 'solid', + optionType: 'button', }, rules: 'required', }, { - fieldName: 'dataFormat', - label: '数据格式', + fieldName: 'status', + label: '产品状态', component: 'RadioGroup', componentProps: { - options: getDictOptions(DICT_TYPE.IOT_DATA_FORMAT, 'number'), + options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), buttonStyle: 'solid', optionType: 'button', }, rules: 'required', }, + { + fieldName: 'icon', + label: '产品图标', + component: 'ImageUpload', + }, + { + fieldName: 'picUrl', + label: '产品图片', + component: 'ImageUpload', + }, { fieldName: 'description', label: '产品描述', @@ -95,13 +157,121 @@ export function useFormSchema(): VbenFormSchema[] { placeholder: '请输入产品描述', rows: 3, }, + } + ]; +} + +/** 基础表单字段(不含图标、图片、描述) */ +export function useBasicFormSchema(formApi?: any): VbenFormSchema[] { + return [ + { + component: 'Input', + fieldName: 'id', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + // 创建时的 ProductKey 字段(带生成按钮) + { + fieldName: 'productKey', + label: 'ProductKey', + component: 'Input', + componentProps: { + placeholder: '请输入 ProductKey', + }, + dependencies: { + triggerFields: ['id'], + if(values) { + // 仅在创建时显示(没有 id) + return !values.id; + }, + }, + rules: z + .string() + .min(1, 'ProductKey 不能为空') + .max(32, 'ProductKey 长度不能超过 32 个字符'), + suffix: () => { + return h(Button, { + type: 'default', + onClick: () => { + formApi?.setFieldValue('productKey', generateProductKey()); + }, + }, { default: () => '重新生成' }); + }, + }, + // 编辑时的 ProductKey 字段(禁用,无按钮) + { + fieldName: 'productKey', + label: 'ProductKey', + component: 'Input', + componentProps: { + placeholder: '请输入 ProductKey', + disabled: true, + }, + dependencies: { + triggerFields: ['id'], + if(values) { + // 仅在编辑时显示(有 id) + return !!values.id; + }, + }, + rules: z + .string() + .min(1, 'ProductKey 不能为空') + .max(32, 'ProductKey 长度不能超过 32 个字符'), + }, + { + fieldName: 'name', + label: '产品名称', + component: 'Input', + componentProps: { + placeholder: '请输入产品名称', + }, + rules: z + .string() + .min(1, '产品名称不能为空') + .max(64, '产品名称长度不能超过 64 个字符'), + }, + { + fieldName: 'categoryId', + label: '产品分类', + component: 'ApiSelect', + componentProps: { + api: getSimpleProductCategoryList, + labelField: 'name', + valueField: 'id', + placeholder: '请选择产品分类', + }, + rules: 'required', + }, + { + fieldName: 'deviceType', + label: '设备类型', + component: 'RadioGroup', + componentProps: { + options: getDictOptions(DICT_TYPE.IOT_PRODUCT_DEVICE_TYPE, 'number'), + buttonStyle: 'solid', + optionType: 'button', + }, + rules: 'required', + }, + { + fieldName: 'netType', + label: '联网方式', + component: 'Select', + componentProps: { + options: getDictOptions(DICT_TYPE.IOT_NET_TYPE, 'number'), + placeholder: '请选择联网方式', + }, + rules: 'required', }, { - fieldName: 'validateType', - label: '认证方式', + fieldName: 'codecType', + label: '数据格式', component: 'RadioGroup', componentProps: { - options: getDictOptions(DICT_TYPE.IOT_VALIDATE_TYPE, 'number'), + options: getDictOptions(DICT_TYPE.IOT_CODEC_TYPE, 'string'), buttonStyle: 'solid', optionType: 'button', }, @@ -118,6 +288,47 @@ export function useFormSchema(): VbenFormSchema[] { }, rules: 'required', }, + { + fieldName: 'locationType', + label: '定位类型', + component: 'Select', + componentProps: { + options: getDictOptions(DICT_TYPE.IOT_LOCATION_TYPE, 'number'), + placeholder: '请选择定位类型', + }, + rules: 'required', + } + ]; +} + +/** 高级设置表单字段(图标、图片、产品描述) */ +export function useAdvancedFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'icon', + label: '产品图标', + component: 'IconPicker',//用这个组件 产品卡片列表 可以根据这个显示 否则就显示默认的 + componentProps: { + placeholder: '请选择产品图标', + prefix: 'carbon', + autoFetchApi: false, + }, + }, + { + fieldName: 'picUrl', + label: '产品图片', + component: 'ImageUpload', + }, + { + fieldName: 'description', + label: '产品描述', + component: 'Textarea', + componentProps: { + placeholder: '请输入产品描述', + rows: 3, + }, + formItemClass: 'col-span-2', // 让描述占满两列 + }, ]; } @@ -226,3 +437,13 @@ export function useImagePreview() { handlePreviewImage, }; } + +/** 生成 ProductKey(包含大小写字母和数字) */ +export function generateProductKey(): string { + const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + let result = ''; + for (let i = 0; i < 16; i++) { + result += chars.charAt(Math.floor(Math.random() * chars.length)); + } + return result; +} 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 ad056a811810c290a4cc53356d798bd879cfa92c..190da4a1830c3b872b4708257888575f1dd7a650 100644 --- a/apps/web-antd/src/views/iot/product/product/index.vue +++ b/apps/web-antd/src/views/iot/product/product/index.vue @@ -15,7 +15,7 @@ import { deleteProduct, exportProduct, getProductPage, -} from '#/api/crm/product'; +} from '#/api/iot/product/product'; import { getSimpleProductCategoryList } from '#/api/iot/product/category'; import { $t } from '#/locales'; diff --git a/apps/web-antd/src/views/iot/product/product/modules/ProductCardView.vue b/apps/web-antd/src/views/iot/product/product/modules/ProductCardView.vue index 124428fb94b3ebb4686489e9b1522235e3c8d143..e28090822ec73acfddfa6a41b1715b4858cf38c4 100644 --- a/apps/web-antd/src/views/iot/product/product/modules/ProductCardView.vue +++ b/apps/web-antd/src/views/iot/product/product/modules/ProductCardView.vue @@ -117,7 +117,7 @@ defineExpose({