Compare commits

...

2 Commits

Author SHA1 Message Date
ChenYi
c6b8339a02 更新接口 2025-07-29 17:32:30 +08:00
ChenYi
57d65c7e77 完成OneNET产品管理 2025-07-29 14:43:27 +08:00
10 changed files with 328 additions and 190 deletions

View File

@ -585,7 +585,7 @@ export const CreateDataDictinaryInputSchema = {
} as const; } as const;
export const CreateDeviceAggregationInputSchema = { export const CreateDeviceAggregationInputSchema = {
required: ['deviceAddress', 'ioTPlatform', 'ioTPlatformProductId', 'platformPassword'], required: ['deviceAddress', 'ioTPlatform', 'ioTPlatformProductId'],
type: 'object', type: 'object',
properties: { properties: {
deviceAddress: { deviceAddress: {
@ -596,25 +596,10 @@ export const CreateDeviceAggregationInputSchema = {
ioTPlatform: { ioTPlatform: {
'$ref': '#/components/schemas/IoTPlatformTypeEnum' '$ref': '#/components/schemas/IoTPlatformTypeEnum'
}, },
platformPassword: {
minLength: 1,
type: 'string',
description: '电表密码'
},
ioTPlatformProductId: { ioTPlatformProductId: {
minLength: 1, minLength: 1,
type: 'string', type: 'string',
description: '集中器在物联网平台中对应的产品Id' description: '集中器在物联网平台中对应的产品Id'
},
ioTPlatformDeviceOpenInfo: {
type: 'string',
description: '集中器在物联网平台中对应的设备Id或者名称',
nullable: true
},
ioTPlatformAccountId: {
type: 'string',
description: '物联网平台中对应的账号Id',
nullable: true
} }
}, },
additionalProperties: false, additionalProperties: false,
@ -1216,6 +1201,10 @@ export const DeviceManagementInfoDtoSchema = {
type: 'string', type: 'string',
description: '物联网平台返回的响应信息', description: '物联网平台返回的响应信息',
nullable: true nullable: true
},
isPlatformPushSuccess: {
type: 'boolean',
description: '物联网平台推送是否成功'
} }
}, },
additionalProperties: false additionalProperties: false

File diff suppressed because one or more lines are too long

View File

@ -215,22 +215,10 @@ export type CreateDeviceAggregationInput = {
*/ */
deviceAddress: string; deviceAddress: string;
ioTPlatform: IoTPlatformTypeEnum; ioTPlatform: IoTPlatformTypeEnum;
/**
*
*/
platformPassword: string;
/** /**
* Id * Id
*/ */
ioTPlatformProductId: string; ioTPlatformProductId: string;
/**
* Id或者名称
*/
ioTPlatformDeviceOpenInfo?: (string) | null;
/**
* Id
*/
ioTPlatformAccountId?: (string) | null;
}; };
/** /**
@ -557,6 +545,10 @@ export type DeviceManagementInfoDto = {
* *
*/ */
ioTPlatformResponse?: (string) | null; ioTPlatformResponse?: (string) | null;
/**
*
*/
isPlatformPushSuccess?: boolean;
}; };
export type DeviceManagementInfoDtoPagedResultDto = { export type DeviceManagementInfoDtoPagedResultDto = {
@ -4522,6 +4514,16 @@ export type PostAggregationDeviceFindByIdAsyncResponse = (DeviceManagementInfoDt
export type PostAggregationDeviceFindByIdAsyncError = unknown; export type PostAggregationDeviceFindByIdAsyncError = unknown;
export type PostAggregationDeviceRepushDeviceInfoToIoTplatformData = {
query?: {
input?: IdInput;
};
};
export type PostAggregationDeviceRepushDeviceInfoToIoTplatformResponse = (DeviceManagementInfoDto);
export type PostAggregationDeviceRepushDeviceInfoToIoTplatformError = unknown;
export type PostDeviceInfoFindByDeviceAddressData = { export type PostDeviceInfoFindByDeviceAddressData = {
query?: { query?: {
deviceAddress?: string; deviceAddress?: string;

View File

@ -276,6 +276,10 @@
"BelongingProductName": "Belonging ProductName", "BelongingProductName": "Belonging ProductName",
"CommunicationAddress": "Communication Address", "CommunicationAddress": "Communication Address",
"CommunicationAddressTLS": "TLS Communication Address", "CommunicationAddressTLS": "TLS Communication Address",
"DeviceThingModelFileName": "DeviceThingModelFileName" "DeviceThingModelFileName": "DeviceThingModelFileName",
"IoTPlatformProductUpdateTime": "ProductUpdateTime",
"IoTPlatformProductCreateTime": "ProductCreateTime",
"CreationTime": "CreationTime",
"LastModificationTime": "LastModificationTime"
} }
} }

View File

@ -55,5 +55,7 @@
"getDataFailed": "Failed to get data", "getDataFailed": "Failed to get data",
"PhoneNumberFormatError": "PhoneNumber Format Error", "PhoneNumberFormatError": "PhoneNumber Format Error",
"IoTPlatform": "IoTPlatform", "IoTPlatform": "IoTPlatform",
"note": "note" "note": "note",
"creationTime": "CreationTime",
"lastModificationTime": "LastModificationTime"
} }

View File

@ -278,6 +278,10 @@
"BelongingProductName": "所属产品", "BelongingProductName": "所属产品",
"CommunicationAddress": "通讯地址", "CommunicationAddress": "通讯地址",
"CommunicationAddressTLS": "TLS通讯地址", "CommunicationAddressTLS": "TLS通讯地址",
"DeviceThingModelFileName": "物模型文件" "DeviceThingModelFileName": "物模型文件",
"IoTPlatformProductUpdateTime": "平台更新时间",
"IoTPlatformProductCreateTime": "平台创建时间",
"CreationTime": "创建时间",
"LastModificationTime": "更新时间"
} }
} }

View File

@ -56,5 +56,7 @@
"IsEnabled": "是否启用", "IsEnabled": "是否启用",
"PhoneNumberFormatError": "手机号码格式错误", "PhoneNumberFormatError": "手机号码格式错误",
"IoTPlatform": "物联网平台", "IoTPlatform": "物联网平台",
"note": "备注" "note": "备注",
"creationTime": "创建时间",
"lastModificationTime": "最后更新时间"
} }

View File

@ -137,7 +137,7 @@ export const addDeviceFormSchema: any = computed(() => [
pageSize: 1000, pageSize: 1000,
}, },
}, },
labelField: 'ProductName', labelField: 'label',
valueField: 'ioTPlatformProductId', valueField: 'ioTPlatformProductId',
immediate: true, immediate: true,
afterFetch: (res: any) => { afterFetch: (res: any) => {
@ -146,34 +146,29 @@ export const addDeviceFormSchema: any = computed(() => [
const data = res.data; const data = res.data;
// 确保返回的是数组格式 // 确保返回的是数组格式
let items = [];
if (Array.isArray(data)) { if (Array.isArray(data)) {
return data; items = data;
} } else if (data && Array.isArray(data.items)) {
// 如果是包装在 items 中的,提取出来 items = data.items;
if (data && Array.isArray(data.items)) { } else if (data && Array.isArray(data.data)) {
return data.items; items = data.data;
}
// 如果是包装在 data 中的,提取出来
if (data && Array.isArray(data.data)) {
return data.data;
} }
// 为每个产品项添加组合标签
return items.map((item: any) => ({
...item,
label: `${item.productName || item.ProductName || ''} (${item.ioTPlatformProductId || ''})`,
}));
} }
// 如果都不是,返回空数组 // 如果都不是,返回空数组
return []; return [];
}, },
placeholder: `${$t('common.pleaseSelect')}${$t('abp.OneNETManagement.BelongingAccountName')}`, placeholder: `${$t('common.pleaseSelect')}${$t('abp.OneNETManagement.BelongingProductName')}`,
}, },
rules: z.string().min(1, { rules: z.string().min(1, {
message: `${$t('common.pleaseSelect')}${$t('abp.OneNETManagement.BelongingAccountName')}`, message: `${$t('common.pleaseSelect')}${$t('abp.OneNETManagement.BelongingProductName')}`,
}),
},
{
component: 'Input',
fieldName: 'deviceName',
label: $t('abp.deviceInfos.deviceName'),
rules: z.string().min(1, {
message: `${$t('common.pleaseInput')}${$t('abp.deviceInfos.deviceName')}`,
}), }),
}, },
{ {
@ -184,14 +179,6 @@ export const addDeviceFormSchema: any = computed(() => [
message: `${$t('common.pleaseInput')}${$t('abp.deviceInfos.deviceAddress')}`, message: `${$t('common.pleaseInput')}${$t('abp.deviceInfos.deviceAddress')}`,
}), }),
}, },
{
component: 'Input',
fieldName: 'platformPassword',
label: $t('abp.deviceInfos.platformPassword'),
rules: z.string().min(1, {
message: `${$t('common.pleaseInput')}${$t('common.info')}${$t('abp.deviceInfos.platformPassword')}`,
}),
},
]); ]);
export const editDeviceFormSchemaEdit: any = computed(() => [ export const editDeviceFormSchemaEdit: any = computed(() => [
@ -240,7 +227,7 @@ export const editDeviceFormSchemaEdit: any = computed(() => [
pageSize: 1000, pageSize: 1000,
}, },
}, },
labelField: 'ProductName', labelField: 'label',
valueField: 'ioTPlatformProductId', valueField: 'ioTPlatformProductId',
immediate: true, immediate: true,
afterFetch: (res: any) => { afterFetch: (res: any) => {
@ -249,26 +236,29 @@ export const editDeviceFormSchemaEdit: any = computed(() => [
const data = res.data; const data = res.data;
// 确保返回的是数组格式 // 确保返回的是数组格式
let items = [];
if (Array.isArray(data)) { if (Array.isArray(data)) {
return data; items = data;
} } else if (data && Array.isArray(data.items)) {
// 如果是包装在 items 中的,提取出来 items = data.items;
if (data && Array.isArray(data.items)) { } else if (data && Array.isArray(data.data)) {
return data.items; items = data.data;
}
// 如果是包装在 data 中的,提取出来
if (data && Array.isArray(data.data)) {
return data.data;
} }
// 为每个产品项添加组合标签
return items.map((item: any) => ({
...item,
label: `${item.productName || item.ProductName || ''} (${item.ioTPlatformProductId || ''})`,
}));
} }
// 如果都不是,返回空数组 // 如果都不是,返回空数组
return []; return [];
}, },
placeholder: `${$t('common.pleaseSelect')}${$t('abp.OneNETManagement.BelongingAccountName')}`, placeholder: `${$t('common.pleaseSelect')}${$t('abp.OneNETManagement.BelongingProductName')}`,
}, },
rules: z.string().min(1, { rules: z.string().min(1, {
message: `${$t('common.pleaseSelect')}${$t('abp.OneNETManagement.BelongingAccountName')}`, message: `${$t('common.pleaseSelect')}${$t('abp.OneNETManagement.BelongingProductName')}`,
}), }),
}, },
{ {

View File

@ -2,7 +2,7 @@
import type { VbenFormProps } from '#/adapter/form'; import type { VbenFormProps } from '#/adapter/form';
import type { VxeGridProps } from '#/adapter/vxe-table'; import type { VxeGridProps } from '#/adapter/vxe-table';
import { h, ref, nextTick } from 'vue'; import { h, nextTick, ref } from 'vue';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
import { Page, useVbenModal } from '@vben/common-ui'; import { Page, useVbenModal } from '@vben/common-ui';
@ -12,12 +12,13 @@ import { message as Message, Tag } from 'ant-design-vue';
import { useVbenForm } from '#/adapter/form'; import { useVbenForm } from '#/adapter/form';
import { useVbenVxeGrid } from '#/adapter/vxe-table'; import { useVbenVxeGrid } from '#/adapter/vxe-table';
import { import {
postOneNetProductInsertAsync, postFilesDownload,
postFilesUpload,
postOneNetProductDeleteAsync, postOneNetProductDeleteAsync,
postOneNetProductInsertAsync,
postOneNetProductListAsync, postOneNetProductListAsync,
postOneNetProductModifyAsync, postOneNetProductModifyAsync,
postFilesUpload, postOneNetProductProductStatusChangeAsync,
postFilesDownload,
} 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';
@ -26,8 +27,8 @@ import {
addProductFormSchema, addProductFormSchema,
editProductFormSchemaEdit, editProductFormSchemaEdit,
querySchema, querySchema,
tableSchema,
setFileSelectedCallback, setFileSelectedCallback,
tableSchema,
} from './schema'; } from './schema';
defineOptions({ defineOptions({
@ -148,12 +149,14 @@ const [EditForm, editFormApi] = useVbenForm({
async function submit() { async function submit() {
const isEdit = !!editRow.value.id; const isEdit = !!editRow.value.id;
const formApi = isEdit ? editFormApi : addFormApi; const formApi = isEdit ? editFormApi : addFormApi;
const api = isEdit ? postOneNetProductModifyAsync : postOneNetProductInsertAsync; const api = isEdit
? postOneNetProductModifyAsync
: postOneNetProductInsertAsync;
const { valid } = await formApi.validate(); const { valid } = await formApi.validate();
if (!valid) return; if (!valid) return;
const formValues = await formApi.getValues(); const formValues = await formApi.getValues();
// //
if (!formValues.deviceThingModelFileName) { if (!formValues.deviceThingModelFileName) {
Message.error('请选择设备模型文件'); Message.error('请选择设备模型文件');
@ -180,7 +183,7 @@ async function submit() {
userModalApi.setState({ loading: false, confirmLoading: false }); userModalApi.setState({ loading: false, confirmLoading: false });
return; return;
} }
} catch (error) { } catch {
Message.error('文件上传失败'); Message.error('文件上传失败');
userModalApi.setState({ loading: false, confirmLoading: false }); userModalApi.setState({ loading: false, confirmLoading: false });
return; return;
@ -191,15 +194,15 @@ async function submit() {
selectedFile = null; selectedFile = null;
// //
const fetchParams: any = isEdit const fetchParams: any = isEdit
? { ? {
id: editRow.value.id, id: editRow.value.id,
...formValues, ...formValues,
} }
: { : {
...formValues, ...formValues,
}; };
try { try {
const resp = await api({ body: fetchParams }); const resp = await api({ body: fetchParams });
@ -237,7 +240,9 @@ const openAddModal = async () => {
// //
async function onDel(record: any) { async function onDel(record: any) {
try { try {
const resp = await postOneNetProductDeleteAsync({ body: { id: record.id } }); const resp = await postOneNetProductDeleteAsync({
body: { id: record.id },
});
if (resp.data) { if (resp.data) {
Message.success($t('common.deleteSuccess')); Message.success($t('common.deleteSuccess'));
// //
@ -257,7 +262,7 @@ async function onDownloadFile(record: any) {
Message.error('文件ID不存在无法下载'); Message.error('文件ID不存在无法下载');
return; return;
} }
try { try {
const { data } = await postFilesDownload({ const { data } = await postFilesDownload({
body: { id: record.deviceThingModelFileId }, body: { id: record.deviceThingModelFileId },
@ -266,68 +271,92 @@ async function onDownloadFile(record: any) {
const url = window.URL.createObjectURL(new Blob([data as Blob])); const url = window.URL.createObjectURL(new Blob([data as Blob]));
const link = document.createElement('a'); const link = document.createElement('a');
link.href = url; link.href = url;
link.setAttribute('download', record.deviceThingModelFileName || 'device-model-file'); link.setAttribute(
'download',
record.deviceThingModelFileName || 'device-model-file',
);
document.body.append(link); document.body.append(link);
link.click(); link.click();
link.remove(); link.remove();
window.URL.revokeObjectURL(url); window.URL.revokeObjectURL(url);
Message.success('文件下载成功'); Message.success('文件下载成功');
} catch (error) { } catch {
Message.error('文件下载失败'); Message.error('文件下载失败');
} }
} }
//
async function onStatusChange(record: any) {
try {
const resp = await postOneNetProductProductStatusChangeAsync({
body: {
id: record.id,
enabled: !record.isEnabled,
},
});
if (resp.data) {
Message.success(record.isEnabled ? '禁用成功' : '启用成功');
gridApi.reload();
} else {
Message.error(record.isEnabled ? '禁用失败' : '启用失败');
}
} catch {
Message.error(record.isEnabled ? '禁用失败' : '启用失败');
}
}
</script> </script>
<template> <template>
<Page auto-content-height> <Page auto-content-height>
<Grid> <Grid>
<template #toolbar-actions> <template #toolbar-actions>
<TableAction <TableAction :actions="[
:actions="[ {
{ label: $t('common.add'),
label: $t('common.add'), type: 'primary',
type: 'primary', icon: 'ant-design:plus-outlined',
icon: 'ant-design:plus-outlined', onClick: openAddModal.bind(null),
onClick: openAddModal.bind(null), auth: ['AbpIdentity.Users.Create'],
auth: ['AbpIdentity.Users.Create'], },
}, ]" />
]"
/>
</template> </template>
<template #isEnable="{ row }"> <template #isEnable="{ row }">
<component <component :is="h(Tag, { color: row.isEnabled ? 'green' : 'red' }, () =>
:is=" row.isEnabled ? $t('common.yes') : $t('common.no'),
h(Tag, { color: row.enabled ? 'green' : 'red' }, () => )
row.enabled ? $t('common.yes') : $t('common.no'), " />
)
"
/>
</template> </template>
<template #deviceThingModelFileName="{ row }"> <template #deviceThingModelFileName="{ row }">
<a <a v-if="row.deviceThingModelFileName && row.deviceThingModelFileId" @click="onDownloadFile(row)"
v-if="row.deviceThingModelFileName && row.deviceThingModelFileId" style="color: #1890ff; text-decoration: underline; cursor: pointer">
@click="onDownloadFile(row)"
style="color: #1890ff; cursor: pointer; text-decoration: underline;"
>
{{ row.deviceThingModelFileName }} {{ row.deviceThingModelFileName }}
</a> </a>
<span v-else>{{ row.deviceThingModelFileName || '-' }}</span> <span v-else>{{ row.deviceThingModelFileName || '-' }}</span>
</template> </template>
<template #action="{ row }"> <template #action="{ row }">
<TableAction <TableAction :actions="[
:actions="[ {
{ label: $t('common.edit'),
label: $t('common.edit'), type: 'link',
type: 'link', size: 'small',
size: 'small', auth: ['AbpIdentity.Users.Update'],
auth: ['AbpIdentity.Users.Update'], onClick: onEdit.bind(null, row),
onClick: onEdit.bind(null, row), },
{
label: row.isEnabled ? '禁用' : '启用',
type: 'link',
danger: row.isEnabled,
size: 'small',
auth: ['AbpIdentity.Users.Update'],
popConfirm: {
title: `确定要${row.isEnabled ? '禁用' : '启用'}该产品吗?`,
confirm: onStatusChange.bind(null, row),
}, },
]" },
:drop-down-actions="[ ]" :drop-down-actions="[
{ {
label: $t('common.delete'), label: $t('common.delete'),
icon: 'ant-design:delete-outlined', icon: 'ant-design:delete-outlined',
@ -338,14 +367,10 @@ async function onDownloadFile(record: any) {
confirm: onDel.bind(null, row), confirm: onDel.bind(null, row),
}, },
}, },
]" ]" />
/>
</template> </template>
</Grid> </Grid>
<UserModal <UserModal :title="editRow.id ? $t('common.edit') : $t('common.add')" class="w-[800px]">
:title="editRow.id ? $t('common.edit') : $t('common.add')"
class="w-[800px]"
>
<component :is="editRow.id ? EditForm : AddForm" /> <component :is="editRow.id ? EditForm : AddForm" />
</UserModal> </UserModal>
</Page> </Page>

View File

@ -4,7 +4,7 @@ import { computed, h } from 'vue';
import { z } from '@vben/common-ui'; import { z } from '@vben/common-ui';
import { postOneNetAccountListAsync, postFilesUpload } from '#/api-client'; import { postOneNetAccountListAsync } from '#/api-client';
import { $t } from '#/locales'; import { $t } from '#/locales';
export const querySchema = computed(() => [ export const querySchema = computed(() => [
@ -53,6 +53,82 @@ export const tableSchema: any = computed((): VxeGridProps['columns'] => [
minWidth: '150', minWidth: '150',
slots: { default: 'deviceThingModelFileName' }, slots: { default: 'deviceThingModelFileName' },
}, },
{
field: 'productCreateTime',
title: $t('abp.OneNETManagement.IoTPlatformProductCreateTime'),
minWidth: '150',
formatter: ({ cellValue }: any) => {
if (!cellValue) return '-';
const date = new Date(cellValue);
if (isNaN(date.getTime())) return '-';
return date.toLocaleString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
hour12: false,
}).replace(/\//g, '-');
},
},
{
field: 'productUpdateTime',
title: $t('abp.OneNETManagement.IoTPlatformProductUpdateTime'),
minWidth: '150',
formatter: ({ cellValue }: any) => {
if (!cellValue) return '-';
const date = new Date(cellValue);
if (isNaN(date.getTime())) return '-';
return date.toLocaleString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
hour12: false,
}).replace(/\//g, '-');
},
},
{
field: 'creationTime',
title: $t('abp.OneNETManagement.CreationTime'),
minWidth: '150',
formatter: ({ cellValue }: any) => {
if (!cellValue) return '-';
const date = new Date(cellValue);
if (isNaN(date.getTime())) return '-';
return date.toLocaleString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
hour12: false,
}).replace(/\//g, '-');
},
},
{
field: 'lastModificationTime',
title: $t('abp.OneNETManagement.LastModificationTime'),
minWidth: '150',
formatter: ({ cellValue }: any) => {
if (!cellValue) return '-';
const date = new Date(cellValue);
if (isNaN(date.getTime())) return '-';
return date.toLocaleString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
hour12: false,
}).replace(/\//g, '-');
},
},
{ {
field: 'isEnabled', field: 'isEnabled',
title: $t('common.isEnable'), title: $t('common.isEnable'),
@ -63,7 +139,7 @@ export const tableSchema: any = computed((): VxeGridProps['columns'] => [
title: $t('common.action'), title: $t('common.action'),
field: 'action', field: 'action',
fixed: 'right', fixed: 'right',
width: '150', width: '200',
slots: { default: 'action' }, slots: { default: 'action' },
}, },
]); ]);
@ -161,37 +237,54 @@ export const addProductFormSchema: any = computed(() => [
componentProps: { componentProps: {
placeholder: '请选择文件', placeholder: '请选择文件',
readonly: true, readonly: true,
addonAfter: h('button', { addonAfter: h(
type: 'button', 'button',
style: 'border: none; background: #1890ff; color: white; padding: 4px 8px; border-radius: 4px; cursor: pointer;', {
onClick: () => { type: 'button',
const input = document.createElement('input'); style:
input.type = 'file'; 'border: none; background: #1890ff; color: white; padding: 4px 8px; border-radius: 4px; cursor: pointer;',
input.accept = '.json,.xlsx,.xls'; onClick: () => {
input.onchange = (e: any) => { const input = document.createElement('input');
const file = e.target.files[0]; input.type = 'file';
if (file) { input.accept = '.json,.xlsx,.xls';
// 只显示文件名,不上传 input.addEventListener('change', (e: any) => {
const currentInput = document.querySelector('input[placeholder="请选择文件"]') as HTMLInputElement; const file = e.target.files[0];
if (currentInput) { if (file) {
currentInput.value = file.name; // 只显示文件名,不上传
// 触发change事件 const currentInput = document.querySelector(
currentInput.dispatchEvent(new Event('input', { bubbles: true })); 'input[placeholder="请选择文件"]',
currentInput.dispatchEvent(new Event('change', { bubbles: true })); ) as HTMLInputElement;
if (currentInput) {
// 存储文件对象到全局变量,用于后续上传 currentInput.value = file.name;
selectedFile = file; // 触发change事件
// 调用回调函数 currentInput.dispatchEvent(
if (_onFileSelected) { new Event('input', { bubbles: true }),
_onFileSelected(file); );
currentInput.dispatchEvent(
new Event('change', { bubbles: true }),
);
// 存储文件对象到全局变量,用于后续上传
selectedFile = file;
// 调用回调函数
if (_onFileSelected) {
_onFileSelected(file);
}
} }
console.log(
'文件已选择:',
file.name,
'大小:',
file.size,
'字节',
);
} }
console.log('文件已选择:', file.name, '大小:', file.size, '字节'); });
} input.click();
}; },
input.click(); },
} '选择文件',
}, '选择文件'), ),
}, },
rules: z.string().min(1, { rules: z.string().min(1, {
message: `${$t('common.pleaseSelect')}${$t('abp.OneNETManagement.DeviceThingModelFileName')}`, message: `${$t('common.pleaseSelect')}${$t('abp.OneNETManagement.DeviceThingModelFileName')}`,
@ -299,37 +392,54 @@ export const editProductFormSchemaEdit: any = computed(() => [
componentProps: { componentProps: {
placeholder: '请选择文件', placeholder: '请选择文件',
readonly: true, readonly: true,
addonAfter: h('button', { addonAfter: h(
type: 'button', 'button',
style: 'border: none; background: #1890ff; color: white; padding: 4px 8px; border-radius: 4px; cursor: pointer;', {
onClick: () => { type: 'button',
const input = document.createElement('input'); style:
input.type = 'file'; 'border: none; background: #1890ff; color: white; padding: 4px 8px; border-radius: 4px; cursor: pointer;',
input.accept = '.json,.xlsx,.xls'; onClick: () => {
input.onchange = (e: any) => { const input = document.createElement('input');
const file = e.target.files[0]; input.type = 'file';
if (file) { input.accept = '.json,.xlsx,.xls';
// 只显示文件名,不上传 input.addEventListener('change', (e: any) => {
const currentInput = document.querySelector('input[placeholder="请选择文件"]') as HTMLInputElement; const file = e.target.files[0];
if (currentInput) { if (file) {
currentInput.value = file.name; // 只显示文件名,不上传
// 触发change事件 const currentInput = document.querySelector(
currentInput.dispatchEvent(new Event('input', { bubbles: true })); 'input[placeholder="请选择文件"]',
currentInput.dispatchEvent(new Event('change', { bubbles: true })); ) as HTMLInputElement;
if (currentInput) {
// 存储文件对象到全局变量,用于后续上传 currentInput.value = file.name;
selectedFile = file; // 触发change事件
// 调用回调函数 currentInput.dispatchEvent(
if (_onFileSelected) { new Event('input', { bubbles: true }),
_onFileSelected(file); );
currentInput.dispatchEvent(
new Event('change', { bubbles: true }),
);
// 存储文件对象到全局变量,用于后续上传
selectedFile = file;
// 调用回调函数
if (_onFileSelected) {
_onFileSelected(file);
}
} }
console.log(
'文件已选择:',
file.name,
'大小:',
file.size,
'字节',
);
} }
console.log('文件已选择:', file.name, '大小:', file.size, '字节'); });
} input.click();
}; },
input.click(); },
} '选择文件',
}, '选择文件'), ),
}, },
rules: z.string().min(1, { rules: z.string().min(1, {
message: `${$t('common.pleaseSelect')}${$t('abp.OneNETManagement.DeviceThingModelFileName')}`, message: `${$t('common.pleaseSelect')}${$t('abp.OneNETManagement.DeviceThingModelFileName')}`,