OneNET产品完善

This commit is contained in:
ChenYi 2025-07-29 11:17:27 +08:00
parent ee179e1f6d
commit 15dbbc6825
6 changed files with 236 additions and 21 deletions

View File

@ -2071,6 +2071,39 @@ export const FileLoadBalancerOptionsSchema = {
additionalProperties: false additionalProperties: false
} as const; } 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 = { export const FileQoSOptionsSchema = {
type: 'object', type: 'object',
properties: { properties: {
@ -4449,9 +4482,14 @@ export const OneNETProductInfoDtoSchema = {
description: '产品访问密钥', description: '产品访问密钥',
nullable: true nullable: true
}, },
deviceThingModelUrl: { deviceThingModelFileId: {
type: 'string', type: 'string',
description: '设备物模型文件管理地址', description: '设备物模型文件Id',
nullable: true
},
deviceThingModelFileName: {
type: 'string',
description: '设备物模型文件名称',
nullable: true nullable: true
}, },
isEnabled: { isEnabled: {
@ -4773,9 +4811,14 @@ export const OneNetProductInfoModifyInputSchema = {
description: 'TLS通讯服务地址', description: 'TLS通讯服务地址',
nullable: true nullable: true
}, },
deviceThingModelUrl: { deviceThingModelFileId: {
type: 'string', type: 'string',
description: '物模型文件链接', description: '设备物模型文件Id',
nullable: true
},
deviceThingModelFileName: {
type: 'string',
description: '设备物模型文件名称',
nullable: true nullable: true
} }
}, },

View File

@ -917,6 +917,32 @@ export type FileLoadBalancerOptions = {
expiry?: number; expiry?: number;
}; };
/**
*
*/
export type FileObjectDto = {
/**
* Id
*/
id?: string;
/**
*
*/
creationTime?: string;
/**
*
*/
fileSize?: number;
/**
*
*/
contentType?: (string) | null;
/**
*
*/
fileName?: (string) | null;
};
export type FileQoSOptions = { export type FileQoSOptions = {
exceptionsAllowedBeforeBreaking?: number; exceptionsAllowedBeforeBreaking?: number;
durationOfBreak?: number; durationOfBreak?: number;
@ -2124,9 +2150,13 @@ export type OneNETProductInfoDto = {
*/ */
productAccesskey?: (string) | null; productAccesskey?: (string) | null;
/** /**
* * Id
*/ */
deviceThingModelUrl?: (string) | null; deviceThingModelFileId?: (string) | null;
/**
*
*/
deviceThingModelFileName?: (string) | null;
/** /**
* *
*/ */
@ -2286,9 +2316,13 @@ export type OneNetProductInfoModifyInput = {
*/ */
communicationAddressTLS?: (string) | null; 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<FileObjectDto>);
export type PostFilesUploadError = (RemoteServiceErrorResponse); export type PostFilesUploadError = (RemoteServiceErrorResponse);

View File

@ -276,6 +276,6 @@
"BelongingProductName": "Belonging ProductName", "BelongingProductName": "Belonging ProductName",
"CommunicationAddress": "Communication Address", "CommunicationAddress": "Communication Address",
"CommunicationAddressTLS": "TLS Communication Address", "CommunicationAddressTLS": "TLS Communication Address",
"DeviceThingModelUrl": "DeviceThingModelUrl" "DeviceThingModelFileName": "DeviceThingModelFileName"
} }
} }

View File

@ -276,8 +276,8 @@
"ProductAccesskey": "产品密钥", "ProductAccesskey": "产品密钥",
"IsEncrypted": "是否加密", "IsEncrypted": "是否加密",
"BelongingProductName": "所属产品", "BelongingProductName": "所属产品",
"CommunicationAddress": "通讯服务地址", "CommunicationAddress": "通讯地址",
"CommunicationAddressTLS": "TLS通讯服务地址", "CommunicationAddressTLS": "TLS通讯地址",
"DeviceThingModelUrl": "物模型文件链接" "DeviceThingModelFileName": "物模型文件"
} }
} }

View File

@ -16,6 +16,7 @@ import {
postOneNetProductDeleteAsync, postOneNetProductDeleteAsync,
postOneNetProductListAsync, postOneNetProductListAsync,
postOneNetProductModifyAsync, postOneNetProductModifyAsync,
postFilesUpload,
} from '#/api-client'; } from '#/api-client';
import { TableAction } from '#/components/table-action'; import { TableAction } from '#/components/table-action';
import { $t } from '#/locales'; import { $t } from '#/locales';
@ -122,6 +123,13 @@ async function submit() {
if (!valid) return; if (!valid) return;
const formValues = await formApi.getValues(); const formValues = await formApi.getValues();
// DeviceThingModelUrl
if (!formValues.DeviceThingModelFileId) {
Message.error('请选择设备模型文件');
return;
}
const fetchParams: any = isEdit const fetchParams: any = isEdit
? { ? {
id: editRow.value.id, id: editRow.value.id,

View File

@ -1,10 +1,10 @@
import type { VxeGridProps } from '#/adapter/vxe-table'; import type { VxeGridProps } from '#/adapter/vxe-table';
import { computed } from 'vue'; import { computed, h } from 'vue';
import { z } from '@vben/common-ui'; import { z } from '@vben/common-ui';
import { postOneNetAccountListAsync } from '#/api-client'; import { postOneNetAccountListAsync, postFilesUpload } from '#/api-client';
import { $t } from '#/locales'; import { $t } from '#/locales';
export const querySchema = computed(() => [ export const querySchema = computed(() => [
@ -140,12 +140,77 @@ export const addProductFormSchema: any = computed(() => [
}, },
{ {
component: 'Input', component: 'Input',
fieldName: 'DeviceThingModelUrl', fieldName: 'DeviceThingModelFileId',
label: $t('abp.OneNETManagement.DeviceThingModelUrl'), 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, { 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(() => [ export const editProductFormSchemaEdit: any = computed(() => [
@ -226,10 +291,75 @@ export const editProductFormSchemaEdit: any = computed(() => [
}, },
{ {
component: 'Input', component: 'Input',
fieldName: 'DeviceThingModelUrl', fieldName: 'DeviceThingModelFileId',
label: $t('abp.OneNETManagement.DeviceThingModelUrl'), 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, { 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',
},
},
]); ]);