完善设备端物模型管理

This commit is contained in:
ChenYi 2025-12-24 11:51:37 +08:00
parent 0ffc2a3098
commit 142584be52
8 changed files with 837 additions and 682 deletions

View File

@ -1312,20 +1312,23 @@ export const CopyIoTPlatformThingModelToDeviceInputSchema = {
} as const;
export const CopyStandardThingModelInputSchema = {
required: ['filedTypes', 'ioTPlatform', 'ioTPlatformProductId'],
type: 'object',
properties: {
filedType: {
type: 'string',
description: '物联网平台中对应产品物模型属性或者事件类型 JiShe.ServicePro.Core.DataDictionaryTypeConst',
nullable: true
filedTypes: {
type: 'array',
items: {
type: 'string'
},
description: '物联网平台中对应产品物模型属性或者事件类型 JiShe.ServicePro.Core.DataDictionaryTypeConst'
},
ioTPlatform: {
'$ref': '#/components/schemas/IoTPlatformTypeEnum'
},
ioTPlatformProductId: {
minLength: 1,
type: 'string',
description: '平台产品ID',
nullable: true
description: '平台产品ID'
},
dataDictionaries: {
type: 'array',
@ -2990,6 +2993,11 @@ export const DeviceThingModelPropertyInfoDtoSchema = {
description: '反转获取数量',
format: 'int32',
nullable: true
},
filedTypeName: {
type: 'string',
description: '物模型属性或者事件类型名称',
nullable: true
}
},
additionalProperties: false,
@ -5492,6 +5500,11 @@ export const IoTPlatformThingModelInfoDtoSchema = {
type: 'string',
description: '物联网平台中对应产品物模型标识符扩展,用于扩展结构体类型',
nullable: true
},
filedTypeName: {
type: 'string',
description: '物模型属性或者事件类型名称',
nullable: true
}
},
additionalProperties: false,

View File

@ -547,7 +547,7 @@ export const postDeviceThingModelManagementBuildAnalysisScriptAsync = <ThrowOnEr
};
/**
* ID将解析脚本更新Redis并发布订阅
* ID和解析标识决定是否将解析脚本更新Redis并发布订阅
*/
export const postDeviceThingModelManagementUpdateAnalysisScriptByIdAsync = <ThrowOnError extends boolean = false>(options?: Options<PostDeviceThingModelManagementUpdateAnalysisScriptByIdAsyncData, ThrowOnError>) => {
return (options?.client ?? client).post<PostDeviceThingModelManagementUpdateAnalysisScriptByIdAsyncResponse, PostDeviceThingModelManagementUpdateAnalysisScriptByIdAsyncError, ThrowOnError>({

View File

@ -302,12 +302,12 @@ export type CopyStandardThingModelInput = {
/**
* JiShe.ServicePro.Core.DataDictionaryTypeConst
*/
filedType?: (string) | null;
ioTPlatform?: IoTPlatformTypeEnum;
filedTypes: Array<(string)>;
ioTPlatform: IoTPlatformTypeEnum;
/**
* ID
*/
ioTPlatformProductId?: (string) | null;
ioTPlatformProductId: string;
/**
*
*/
@ -1712,6 +1712,10 @@ export type DeviceThingModelPropertyInfoDto = {
*
*/
reversalTakeNumber?: (number) | null;
/**
*
*/
filedTypeName?: (string) | null;
};
export type DeviceThingModelPropertyInfoDtoPagedResultDto = {
@ -2782,6 +2786,10 @@ export type IoTPlatformThingModelInfoDto = {
*
*/
ioTPlatformRawFieldExtension?: (string) | null;
/**
*
*/
filedTypeName?: (string) | null;
};
export type IoTPlatformThingModelInfoDtoPagedResultDto = {

View File

@ -44,7 +44,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
gridOptions: {
columns: [
{
field: 'filedType',
field: 'filedTypeName',
title: '物模型类型',
minWidth: 160,
showOverflow: 'tooltip',
@ -223,6 +223,7 @@ const [EditPropertyFormModal, editPropertyFormModalApi] = useVbenModal({
//
const [CopyPropertyModal, copyPropertyModalApi] = useVbenModal({
draggable: true,
centered: true,
footer: true,
showCancelButton: true,
showConfirmButton: true,
@ -598,16 +599,16 @@ watch(
},
);
//
//
const [CopyPropertyForm, copyPropertyFormApi] = useVbenForm({
collapsed: false,
commonConfig: {
labelWidth: 140,
componentProps: {
class: 'w-4/5',
class: 'w-full',
},
},
layout: 'horizontal',
layout: 'vertical',
schema: [
{
component: 'ApiSelect',
@ -690,7 +691,7 @@ const [CopyPropertyForm, copyPropertyFormApi] = useVbenForm({
],
showCollapseButton: false,
showDefaultActions: false,
wrapperClass: 'grid-cols-2',
wrapperClass: 'grid-cols-1',
});
//

View File

@ -634,7 +634,6 @@ onMounted(async () => {
auth: ['AbpIdentity.Users.Update'],
onClick: openPropertyModal.bind(null, row),
},
]" :drop-down-actions="[
{
label: '指令管理',
type: 'link',
@ -642,6 +641,7 @@ onMounted(async () => {
auth: ['AbpIdentity.Users.Update'],
onClick: openCommandModal.bind(null, row),
},
]" :drop-down-actions="[
{
label: row.functionAnalysisFlag ? '禁用解析' : '启用解析',
type: 'input',

View File

@ -152,7 +152,7 @@ export const tableSchema = computed(() => [
{
field: 'action',
title: $t('common.action'),
width: 160,
width: 250,
fixed: 'right',
slots: { default: 'action' },
},

View File

@ -23,8 +23,9 @@ import { TableAction } from '#/components/table-action';
import { $t } from '#/locales';
import {
getAddThingModelFormSchema,
copyStandardThingModelFormSchema,
copyThingModelFormSchema,
getAddThingModelFormSchema,
getEditThingModelFormSchema,
querySchema,
tableSchema,
@ -44,14 +45,17 @@ const ioTPlatform = ref<string>((route.query.ioTPlatform as string) || '2');
const formOptions: VbenFormProps = {
schema: querySchema.value,
initialValues: {
ioTPlatform: route.query.ioTPlatform ? String(route.query.ioTPlatform) : undefined,
ioTPlatformProductId: route.query.productId ? String(route.query.productId) : undefined,
ioTPlatform: route.query.ioTPlatform
? String(route.query.ioTPlatform)
: undefined,
ioTPlatformProductId: route.query.productId
? String(route.query.productId)
: undefined,
},
submitOnChange: false,
handleValuesChange: async (values, changedFields) => {
// ID
if (changedFields.includes('ioTPlatform')) {
if (values.ioTPlatform) {
if (changedFields.includes('ioTPlatform') && values.ioTPlatform) {
ioTPlatform.value = String(values.ioTPlatform);
// ID
if (gridApi?.formApi) {
@ -62,7 +66,6 @@ const formOptions: VbenFormProps = {
productId.value = '';
productName.value = '';
}
}
// ID
if (changedFields.includes('ioTPlatformProductId')) {
@ -115,7 +118,7 @@ const gridOptions: VxeGridProps<any> = {
: formValues || {};
// 使API使formValues
const finalFormValues = { ...(formValues || {}), ...currentFormValues };
const finalFormValues = { ...formValues, ...currentFormValues };
const currentPlatform = finalFormValues?.ioTPlatform;
const currentProductId = finalFormValues?.ioTPlatformProductId;
@ -135,7 +138,9 @@ const gridOptions: VxeGridProps<any> = {
//
if (currentPlatform) {
queryParams.ioTPlatform = Number.parseInt(String(currentPlatform)) as 1 | 2;
queryParams.ioTPlatform = Number.parseInt(
String(currentPlatform),
) as 1 | 2;
}
// ID
@ -192,19 +197,21 @@ const [ThingModelModal, thingModelModalApi] = useVbenModal({
if (isEdit) {
// editRow.value
platformValue = editRow.value.ioTPlatform
? (typeof editRow.value.ioTPlatform === 'string'
? ((typeof editRow.value.ioTPlatform === 'string'
? Number.parseInt(editRow.value.ioTPlatform)
: editRow.value.ioTPlatform) as 1 | 2
: Number.parseInt(ioTPlatform.value) as 1 | 2;
: editRow.value.ioTPlatform) as 1 | 2)
: (Number.parseInt(ioTPlatform.value) as 1 | 2);
productIdValue = editRow.value.ioTPlatformProductId || productId.value;
} else {
//
const formValues = gridApi?.formApi ? await gridApi.formApi.getValues() : {};
const formValues = gridApi?.formApi
? await gridApi.formApi.getValues()
: {};
platformValue = formValues.ioTPlatform
? (typeof formValues.ioTPlatform === 'string'
? ((typeof formValues.ioTPlatform === 'string'
? Number.parseInt(formValues.ioTPlatform)
: formValues.ioTPlatform) as 1 | 2
: Number.parseInt(ioTPlatform.value) as 1 | 2;
: formValues.ioTPlatform) as 1 | 2)
: (Number.parseInt(ioTPlatform.value) as 1 | 2);
productIdValue = formValues.ioTPlatformProductId || productId.value;
//
@ -231,7 +238,9 @@ const [ThingModelModal, thingModelModalApi] = useVbenModal({
//
setTimeout(() => {
const fieldRef = formApi.getFieldComponentRef('ioTPlatformRawFieldName');
const fieldRef = formApi.getFieldComponentRef(
'ioTPlatformRawFieldName',
);
if (fieldRef && typeof fieldRef.updateParam === 'function') {
fieldRef.updateParam({
body: {
@ -262,12 +271,29 @@ const [CopyModal, copyModalApi] = useVbenModal({
},
});
//
const [CopyStandardModal, copyStandardModalApi] = useVbenModal({
draggable: true,
footer: true,
showCancelButton: true,
showConfirmButton: true,
onConfirm: submitCopyStandard,
onBeforeClose: () => {
return true;
},
onCancel: () => {
copyStandardModalApi.close();
},
});
// schemaID
// 使 _ioTPlatform _ioTPlatformProductId
const addThingModelFormSchema = getAddThingModelFormSchema(
() => {
//
return ioTPlatform.value ? Number.parseInt(ioTPlatform.value) as 1 | 2 : undefined;
return ioTPlatform.value
? (Number.parseInt(ioTPlatform.value) as 1 | 2)
: undefined;
},
() => {
//
@ -301,7 +327,9 @@ const editThingModelFormSchema = getEditThingModelFormSchema(
: editRow.value.ioTPlatform;
}
// 使
return ioTPlatform.value ? Number.parseInt(ioTPlatform.value) as 1 | 2 : undefined;
return ioTPlatform.value
? (Number.parseInt(ioTPlatform.value) as 1 | 2)
: undefined;
},
() => {
// editRow
@ -340,6 +368,22 @@ const [CopyForm, copyFormApi] = useVbenForm({
wrapperClass: 'grid-cols-2',
});
//
const [CopyStandardForm, copyStandardFormApi] = useVbenForm({
collapsed: false,
commonConfig: {
labelWidth: 160,
componentProps: {
class: 'w-4/5',
},
},
layout: 'horizontal',
schema: copyStandardThingModelFormSchema.value,
showCollapseButton: false,
showDefaultActions: false,
wrapperClass: 'grid-cols-1',
});
//
watch(
() => [route.query.productId, route.query.ioTPlatform],
@ -451,9 +495,6 @@ async function submit() {
}
} catch (error) {
console.error('提交失败:', error);
Message.error(
editRow.value.id ? $t('common.editFail') : $t('common.addFail'),
);
}
}
@ -461,10 +502,10 @@ async function onEdit(record: any) {
editRow.value = record;
// ID
const platformValue = record.ioTPlatform
? (typeof record.ioTPlatform === 'string'
? ((typeof record.ioTPlatform === 'string'
? Number.parseInt(record.ioTPlatform)
: record.ioTPlatform) as 1 | 2
: Number.parseInt(ioTPlatform.value) as 1 | 2;
: record.ioTPlatform) as 1 | 2)
: (Number.parseInt(ioTPlatform.value) as 1 | 2);
const productIdValue = record.ioTPlatformProductId || productId.value;
thingModelModalApi.open();
@ -477,7 +518,9 @@ async function onEdit(record: any) {
});
//
const fieldRef = editFormApi.getFieldComponentRef('ioTPlatformRawFieldName');
const fieldRef = editFormApi.getFieldComponentRef(
'ioTPlatformRawFieldName',
);
if (fieldRef && typeof fieldRef.updateParam === 'function') {
fieldRef.updateParam({
body: {
@ -494,10 +537,10 @@ const openAddModal = async () => {
// ID
const formValues = gridApi?.formApi ? await gridApi.formApi.getValues() : {};
const platformValue = formValues.ioTPlatform
? (typeof formValues.ioTPlatform === 'string'
? ((typeof formValues.ioTPlatform === 'string'
? Number.parseInt(formValues.ioTPlatform)
: formValues.ioTPlatform) as 1 | 2
: Number.parseInt(ioTPlatform.value) as 1 | 2;
: formValues.ioTPlatform) as 1 | 2)
: (Number.parseInt(ioTPlatform.value) as 1 | 2);
const productIdValue = formValues.ioTPlatformProductId || productId.value;
//
@ -580,7 +623,59 @@ async function submitCopy() {
}
} catch (error) {
console.error('复制模型失败:', error);
Message.error('复制模型失败');
}
}
//
const openCopyStandardThingModelModal = () => {
console.log('打开复制标准模型模态框,当前参数:', {
productId: productId.value,
productName: productName.value,
ioTPlatform: ioTPlatform.value,
});
copyStandardModalApi.open();
};
//
async function submitCopyStandard() {
// ID
if (!productId.value) {
Message.error('产品ID不存在无法复制标准模型');
return;
}
const { valid } = await copyStandardFormApi.validate();
if (!valid) return;
const formValues = await copyStandardFormApi.getValues();
console.log('复制标准模型提交参数:', {
formValues,
params: {
productId: productId.value,
productName: productName.value,
ioTPlatform: ioTPlatform.value,
},
});
try {
const resp = await postIoTplatformThingModelInfoCopyStandardThingModel({
body: {
ioTPlatform: Number.parseInt(ioTPlatform.value) as 1 | 2,
ioTPlatformProductId: productId.value,
// 使 filedTypes key
filedTypes: formValues.filedTypes,
},
});
if (resp.data) {
Message.success('复制标准模型成功');
copyStandardModalApi.close();
gridApi.reload();
} else {
Message.error('复制标准模型失败');
}
} catch (error) {
console.error('复制标准模型失败:', error);
}
}
@ -598,36 +693,10 @@ async function onDel(record: any) {
}
} catch (error) {
console.error('删除失败:', error);
Message.error($t('common.deleteFail'));
}
}
//
async function copyStandardThingModel() {
// ID
if (!productId.value) {
Message.error('产品ID不存在无法复制标准模型');
return;
}
try {
const resp = await postIoTplatformThingModelInfoCopyStandardThingModel({
body: {
ioTPlatform: Number.parseInt(ioTPlatform.value) as 1 | 2,
ioTPlatformProductId: productId.value,
},
});
if (resp.data) {
Message.success('复制标准模型成功');
gridApi.reload();
} else {
Message.error('复制标准模型失败');
}
} catch (error) {
console.error('复制标准模型失败:', error);
Message.error('复制标准模型失败');
}
}
// 使 + submitCopyStandard
</script>
<template>
@ -647,7 +716,7 @@ async function copyStandardThingModel() {
label: $t('abp.thingModelInfos.copyStandardThingModel'),
type: 'default',
icon: 'ant-design:copy-outlined',
onClick: copyStandardThingModel,
onClick: openCopyStandardThingModelModal,
auth: ['AbpIdentity.Users.Create'],
disabled: !productId,
},
@ -703,5 +772,10 @@ async function copyStandardThingModel() {
<CopyModal title="复制已有模型" class="w-[600px]">
<CopyForm />
</CopyModal>
<!-- 复制标准模型按物模型类型多选模态框 -->
<CopyStandardModal title="复制标准模型" class="w-[600px]">
<CopyStandardForm />
</CopyStandardModal>
</Page>
</template>

View File

@ -105,7 +105,7 @@ export const querySchema = computed(() => [
export const tableSchema = computed(() => [
{
field: 'filedType',
field: 'filedTypeName',
title: $t('abp.thingModelInfos.FiledType'),
minWidth: 120,
showOverflow: 'tooltip',
@ -180,7 +180,11 @@ export const tableSchema = computed(() => [
]);
// 添加物模型表单schema
export const getAddThingModelFormSchema = (getPlatform: () => number | string | undefined, getProductId: () => string | undefined) => computed(() => [
export const getAddThingModelFormSchema = (
getPlatform: () => number | string | undefined,
getProductId: () => string | undefined,
) =>
computed(() => [
{
component: 'ApiSelect',
fieldName: 'filedType',
@ -276,7 +280,8 @@ export const getAddThingModelFormSchema = (getPlatform: () => number | string |
.toUpperCase();
},
placeholder:
$t('common.pleaseSelect') + $t('abp.thingModelInfos.StandardFieldName'),
$t('common.pleaseSelect') +
$t('abp.thingModelInfos.StandardFieldName'),
}),
},
{
@ -310,7 +315,8 @@ export const getAddThingModelFormSchema = (getPlatform: () => number | string |
// 如果表单值中没有,尝试从其他字段获取
if (!platform && formValues?.ioTPlatform) {
platform = typeof formValues.ioTPlatform === 'string'
platform =
typeof formValues.ioTPlatform === 'string'
? Number.parseInt(formValues.ioTPlatform)
: formValues.ioTPlatform;
}
@ -322,7 +328,8 @@ export const getAddThingModelFormSchema = (getPlatform: () => number | string |
if (!platform) {
const externalPlatform = getPlatform();
if (externalPlatform) {
platform = typeof externalPlatform === 'string'
platform =
typeof externalPlatform === 'string'
? Number.parseInt(externalPlatform)
: externalPlatform;
}
@ -474,13 +481,18 @@ export const getAddThingModelFormSchema = (getPlatform: () => number | string |
label: '平台物模型值类型扩展',
componentProps: {
rows: 4,
placeholder: '请输入平台原始字段扩展信息用于扩展结构体类型JSON格式',
placeholder:
'请输入平台原始字段扩展信息用于扩展结构体类型JSON格式',
},
},
]);
// 编辑物模型表单schema
export const getEditThingModelFormSchema = (getPlatform: () => number | string | undefined, getProductId: () => string | undefined) => computed(() => [
export const getEditThingModelFormSchema = (
getPlatform: () => number | string | undefined,
getProductId: () => string | undefined,
) =>
computed(() => [
{
component: 'ApiSelect',
fieldName: 'filedType',
@ -589,7 +601,8 @@ export const getEditThingModelFormSchema = (getPlatform: () => number | string |
componentProps: {
disabled: true, // 编辑时禁用
placeholder:
$t('common.pleaseSelect') + $t('abp.thingModelInfos.StandardFieldName'),
$t('common.pleaseSelect') +
$t('abp.thingModelInfos.StandardFieldName'),
},
},
{
@ -609,7 +622,8 @@ export const getEditThingModelFormSchema = (getPlatform: () => number | string |
// 如果表单值中没有,尝试从其他字段获取
if (!platform && formValues?.ioTPlatform) {
platform = typeof formValues.ioTPlatform === 'string'
platform =
typeof formValues.ioTPlatform === 'string'
? Number.parseInt(formValues.ioTPlatform)
: formValues.ioTPlatform;
}
@ -621,7 +635,8 @@ export const getEditThingModelFormSchema = (getPlatform: () => number | string |
if (!platform) {
const externalPlatform = getPlatform();
if (externalPlatform) {
platform = typeof externalPlatform === 'string'
platform =
typeof externalPlatform === 'string'
? Number.parseInt(externalPlatform)
: externalPlatform;
}
@ -771,7 +786,8 @@ export const getEditThingModelFormSchema = (getPlatform: () => number | string |
label: '平台物模型值类型扩展',
componentProps: {
rows: 4,
placeholder: '请输入平台原始字段扩展信息用于扩展结构体类型JSON格式',
placeholder:
'请输入平台原始字段扩展信息用于扩展结构体类型JSON格式',
},
},
]);
@ -819,3 +835,46 @@ export const copyThingModelFormSchema = computed(() => [
},
},
]);
// 复制标准模型(按物模型类型多选)表单 schema
export const copyStandardThingModelFormSchema = computed(() => [
{
component: 'ApiSelect',
fieldName: 'filedTypes',
label: '选择要复制的物模型类型',
rules: z.preprocess(
(v) => (v == null ? [] : v),
z.array(z.string()).min(1, '请至少选择一个物模型类型'),
),
componentProps: {
api: getCommonGetSelectList,
params: {
query: {
// 与物模型字段类型相同的数据字典Property / Service / Event
typeName: 'DataDictionaryTypeConst',
},
},
labelField: 'value',
valueField: 'key',
optionsPropName: 'options',
immediate: true,
allowClear: true,
mode: 'multiple',
placeholder: '请选择要复制的物模型类型(可多选)',
maxTagCount: 'responsive',
afterFetch: (res: any) => {
// 确保返回的是数组格式
if (Array.isArray(res)) {
return res;
}
if (res && Array.isArray(res.items)) {
return res.items;
}
if (res && Array.isArray(res.data)) {
return res.data;
}
return [];
},
},
},
]);