diff --git a/apps/web-antd/src/api-client/schemas.gen.ts b/apps/web-antd/src/api-client/schemas.gen.ts index b248a72..df6a48d 100644 --- a/apps/web-antd/src/api-client/schemas.gen.ts +++ b/apps/web-antd/src/api-client/schemas.gen.ts @@ -2071,6 +2071,39 @@ export const FileLoadBalancerOptionsSchema = { additionalProperties: false } as const; +export const FileObjectDtoSchema = { + type: 'object', + properties: { + id: { + type: 'string', + description: '主键Id', + format: 'uuid' + }, + creationTime: { + type: 'string', + description: '创建时间', + format: 'date-time' + }, + fileSize: { + type: 'integer', + description: '文件大小', + format: 'int64' + }, + contentType: { + type: 'string', + description: '文件名称', + nullable: true + }, + fileName: { + type: 'string', + description: '文件名称', + nullable: true + } + }, + additionalProperties: false, + description: '文件' +} as const; + export const FileQoSOptionsSchema = { type: 'object', properties: { @@ -4449,9 +4482,14 @@ export const OneNETProductInfoDtoSchema = { description: '产品访问密钥', nullable: true }, - deviceThingModelUrl: { + deviceThingModelFileId: { type: 'string', - description: '设备物模型文件管理地址', + description: '设备物模型文件Id', + nullable: true + }, + deviceThingModelFileName: { + type: 'string', + description: '设备物模型文件名称', nullable: true }, isEnabled: { @@ -4773,9 +4811,14 @@ export const OneNetProductInfoModifyInputSchema = { description: 'TLS通讯服务地址', nullable: true }, - deviceThingModelUrl: { + deviceThingModelFileId: { type: 'string', - description: '物模型文件链接', + description: '设备物模型文件Id', + nullable: true + }, + deviceThingModelFileName: { + type: 'string', + description: '设备物模型文件名称', nullable: true } }, diff --git a/apps/web-antd/src/api-client/types.gen.ts b/apps/web-antd/src/api-client/types.gen.ts index 2fe0937..de1e315 100644 --- a/apps/web-antd/src/api-client/types.gen.ts +++ b/apps/web-antd/src/api-client/types.gen.ts @@ -917,6 +917,32 @@ export type FileLoadBalancerOptions = { expiry?: number; }; +/** + * 文件 + */ +export type FileObjectDto = { + /** + * 主键Id + */ + id?: string; + /** + * 创建时间 + */ + creationTime?: string; + /** + * 文件大小 + */ + fileSize?: number; + /** + * 文件名称 + */ + contentType?: (string) | null; + /** + * 文件名称 + */ + fileName?: (string) | null; +}; + export type FileQoSOptions = { exceptionsAllowedBeforeBreaking?: number; durationOfBreak?: number; @@ -2124,9 +2150,13 @@ export type OneNETProductInfoDto = { */ productAccesskey?: (string) | null; /** - * 设备物模型文件管理地址 + * 设备物模型文件Id */ - deviceThingModelUrl?: (string) | null; + deviceThingModelFileId?: (string) | null; + /** + * 设备物模型文件名称 + */ + deviceThingModelFileName?: (string) | null; /** * 是否启用 */ @@ -2286,9 +2316,13 @@ export type OneNetProductInfoModifyInput = { */ communicationAddressTLS?: (string) | null; /** - * 物模型文件链接 + * 设备物模型文件Id */ - deviceThingModelUrl?: (string) | null; + deviceThingModelFileId?: (string) | null; + /** + * 设备物模型文件名称 + */ + deviceThingModelFileName?: (string) | null; }; /** @@ -4560,7 +4594,7 @@ export type PostFilesUploadData = { }; }; -export type PostFilesUploadResponse = (unknown); +export type PostFilesUploadResponse = (Array); export type PostFilesUploadError = (RemoteServiceErrorResponse); diff --git a/apps/web-antd/src/locales/langs/en-US/abp.json b/apps/web-antd/src/locales/langs/en-US/abp.json index 4333fac..ba94a93 100644 --- a/apps/web-antd/src/locales/langs/en-US/abp.json +++ b/apps/web-antd/src/locales/langs/en-US/abp.json @@ -276,6 +276,6 @@ "BelongingProductName": "Belonging ProductName", "CommunicationAddress": "Communication Address", "CommunicationAddressTLS": "TLS Communication Address", - "DeviceThingModelUrl": "DeviceThingModelUrl" + "DeviceThingModelFileName": "DeviceThingModelFileName" } } diff --git a/apps/web-antd/src/locales/langs/zh-CN/abp.json b/apps/web-antd/src/locales/langs/zh-CN/abp.json index 87c00b0..1ff6540 100644 --- a/apps/web-antd/src/locales/langs/zh-CN/abp.json +++ b/apps/web-antd/src/locales/langs/zh-CN/abp.json @@ -276,8 +276,8 @@ "ProductAccesskey": "产品密钥", "IsEncrypted": "是否加密", "BelongingProductName": "所属产品", - "CommunicationAddress": "通讯服务地址", - "CommunicationAddressTLS": "TLS通讯服务地址", - "DeviceThingModelUrl": "物模型文件链接" + "CommunicationAddress": "通讯地址", + "CommunicationAddressTLS": "TLS通讯地址", + "DeviceThingModelFileName": "物模型文件" } } diff --git a/apps/web-antd/src/views/onenetmanagement/privateProduct/index.vue b/apps/web-antd/src/views/onenetmanagement/privateProduct/index.vue index d8f27b3..c20cbdb 100644 --- a/apps/web-antd/src/views/onenetmanagement/privateProduct/index.vue +++ b/apps/web-antd/src/views/onenetmanagement/privateProduct/index.vue @@ -16,6 +16,7 @@ import { postOneNetProductDeleteAsync, postOneNetProductListAsync, postOneNetProductModifyAsync, + postFilesUpload, } from '#/api-client'; import { TableAction } from '#/components/table-action'; import { $t } from '#/locales'; @@ -122,6 +123,13 @@ async function submit() { if (!valid) return; const formValues = await formApi.getValues(); + + // 检查DeviceThingModelUrl是否为空 + if (!formValues.DeviceThingModelFileId) { + Message.error('请选择设备模型文件'); + return; + } + const fetchParams: any = isEdit ? { id: editRow.value.id, diff --git a/apps/web-antd/src/views/onenetmanagement/privateProduct/schema.ts b/apps/web-antd/src/views/onenetmanagement/privateProduct/schema.ts index 865ef64..9e81830 100644 --- a/apps/web-antd/src/views/onenetmanagement/privateProduct/schema.ts +++ b/apps/web-antd/src/views/onenetmanagement/privateProduct/schema.ts @@ -1,10 +1,10 @@ import type { VxeGridProps } from '#/adapter/vxe-table'; -import { computed } from 'vue'; +import { computed, h } from 'vue'; import { z } from '@vben/common-ui'; -import { postOneNetAccountListAsync } from '#/api-client'; +import { postOneNetAccountListAsync, postFilesUpload } from '#/api-client'; import { $t } from '#/locales'; export const querySchema = computed(() => [ @@ -140,12 +140,77 @@ export const addProductFormSchema: any = computed(() => [ }, { component: 'Input', - fieldName: 'DeviceThingModelUrl', - label: $t('abp.OneNETManagement.DeviceThingModelUrl'), + fieldName: 'DeviceThingModelFileId', + label: $t('abp.OneNETManagement.DeviceThingModelFileName'), + componentProps: { + placeholder: '请选择文件', + readonly: true, + addonAfter: h('button', { + type: 'button', + style: 'border: none; background: #1890ff; color: white; padding: 4px 8px; border-radius: 4px; cursor: pointer;', + onClick: () => { + const input = document.createElement('input'); + input.type = 'file'; + input.accept = '*/*'; + input.onchange = async (e: any) => { + const file = e.target.files[0]; + if (file) { + try { + const result = await postFilesUpload({ + body: { + files: [file] + } + }); + + if (result.status === 204 || result.status === 200) { + // 假设返回的是文件信息数组,取第一个文件的ID + const fileInfo = result.data?.[0]; + if (fileInfo && fileInfo.id) { + // 查找当前输入框并更新值 + const currentInput = document.querySelector('input[placeholder="请选择文件"]'); + if (currentInput) { + (currentInput as HTMLInputElement).value = fileInfo.id; + // 触发change事件 + currentInput.dispatchEvent(new Event('input', { bubbles: true })); + currentInput.dispatchEvent(new Event('change', { bubbles: true })); + + // 同时设置文件名到隐藏字段 + const fileNameInput = document.querySelector('input[name="DeviceThingModelFileName"]') || + document.querySelector('input[data-field="DeviceThingModelFileName"]'); + if (fileNameInput) { + (fileNameInput as HTMLInputElement).value = file.name; + fileNameInput.dispatchEvent(new Event('input', { bubbles: true })); + fileNameInput.dispatchEvent(new Event('change', { bubbles: true })); + } + } + console.log('文件上传成功,文件ID:', fileInfo.id, '文件名:', file.name); + } else { + console.error('文件上传成功但未获取到文件ID'); + } + } else { + console.error('文件上传失败'); + } + } catch (error) { + console.error('文件上传失败:', error); + } + } + }; + input.click(); + } + }, '选择文件'), + }, rules: z.string().min(1, { - message: `${$t('common.pleaseInput')}${$t('common.info')}${$t('abp.OneNETManagement.DeviceThingModelUrl')}`, + message: `${$t('common.pleaseSelect')}${$t('abp.OneNETManagement.DeviceThingModelFileName')}`, }), }, + { + component: 'Input', + fieldName: 'DeviceThingModelFileName', + label: '', + componentProps: { + type: 'hidden', + }, + }, ]); export const editProductFormSchemaEdit: any = computed(() => [ @@ -226,10 +291,75 @@ export const editProductFormSchemaEdit: any = computed(() => [ }, { component: 'Input', - fieldName: 'DeviceThingModelUrl', - label: $t('abp.OneNETManagement.DeviceThingModelUrl'), + fieldName: 'DeviceThingModelFileId', + label: $t('abp.OneNETManagement.DeviceThingModelFileName'), + componentProps: { + placeholder: '请选择文件', + readonly: true, + addonAfter: h('button', { + type: 'button', + style: 'border: none; background: #1890ff; color: white; padding: 4px 8px; border-radius: 4px; cursor: pointer;', + onClick: () => { + const input = document.createElement('input'); + input.type = 'file'; + input.accept = '*/*'; + input.onchange = async (e: any) => { + const file = e.target.files[0]; + if (file) { + try { + const result = await postFilesUpload({ + body: { + files: [file] + } + }); + + if (result.status === 204 || result.status === 200) { + // 假设返回的是文件信息数组,取第一个文件的ID + const fileInfo = result.data?.[0]; + if (fileInfo && fileInfo.id) { + // 查找当前输入框并更新值 + const currentInput = document.querySelector('input[placeholder="请选择文件"]'); + if (currentInput) { + (currentInput as HTMLInputElement).value = fileInfo.id; + // 触发change事件 + currentInput.dispatchEvent(new Event('input', { bubbles: true })); + currentInput.dispatchEvent(new Event('change', { bubbles: true })); + + // 同时设置文件名到隐藏字段 + const fileNameInput = document.querySelector('input[name="DeviceThingModelFileName"]') || + document.querySelector('input[data-field="DeviceThingModelFileName"]'); + if (fileNameInput) { + (fileNameInput as HTMLInputElement).value = file.name; + fileNameInput.dispatchEvent(new Event('input', { bubbles: true })); + fileNameInput.dispatchEvent(new Event('change', { bubbles: true })); + } + } + console.log('文件上传成功,文件ID:', fileInfo.id, '文件名:', file.name); + } else { + console.error('文件上传成功但未获取到文件ID'); + } + } else { + console.error('文件上传失败'); + } + } catch (error) { + console.error('文件上传失败:', error); + } + } + }; + input.click(); + } + }, '选择文件'), + }, rules: z.string().min(1, { - message: `${$t('common.pleaseInput')}${$t('common.info')}${$t('abp.OneNETManagement.DeviceThingModelUrl')}`, + message: `${$t('common.pleaseSelect')}${$t('abp.OneNETManagement.DeviceThingModelFileName')}`, }), }, + { + component: 'Input', + fieldName: 'DeviceThingModelFileName', + label: '', + componentProps: { + type: 'hidden', + }, + }, ]);