设备端物模型属性完善
This commit is contained in:
parent
cfbe8f4df0
commit
f3ac09394c
@ -126,6 +126,7 @@ export type ComponentType =
|
||||
| 'Select'
|
||||
| 'Space'
|
||||
| 'StandardThingModelCodeSelect'
|
||||
| 'IoTPlatformThingModelDataSelect'
|
||||
| 'Switch'
|
||||
| 'Textarea'
|
||||
| 'TimePicker'
|
||||
@ -181,7 +182,14 @@ async function initComponentAdapter() {
|
||||
StandardThingModelCodeSelect: defineAsyncComponent(
|
||||
() =>
|
||||
import(
|
||||
'#/views/thingmodelinfo/ioTPlatformThingModelInfo/StandardThingModelCodeSelect.vue'
|
||||
'#/views/thingmodelinfo/StandardThingModelCodeSelect.vue'
|
||||
) as any,
|
||||
),
|
||||
// 自定义平台端物模型选择组件(分页搜索)
|
||||
IoTPlatformThingModelDataSelect: defineAsyncComponent(
|
||||
() =>
|
||||
import(
|
||||
'#/views/thingmodelinfo/IoTPlatformThingModelDataSelect.vue'
|
||||
) as any,
|
||||
),
|
||||
// 自定义默认按钮
|
||||
|
||||
@ -2765,7 +2765,7 @@ export const DeviceThingModelPageInputSchema = {
|
||||
} as const;
|
||||
|
||||
export const DeviceThingModelPropertyCreateInputSchema = {
|
||||
required: ['deviceThingModelId', 'ioTPlatformRawFieldDataType', 'ioTPlatformRawFieldName', 'nativeSkipNumber', 'nativeTakeNumber', 'parsingSequence', 'standardFieldDisplayName', 'standardFieldName', 'standardFieldValueType'],
|
||||
required: ['deviceThingModelId', 'nativeSkipNumber', 'nativeTakeNumber', 'parsingSequence'],
|
||||
type: 'object',
|
||||
properties: {
|
||||
deviceThingModelId: {
|
||||
@ -2773,39 +2773,10 @@ export const DeviceThingModelPropertyCreateInputSchema = {
|
||||
description: '设备端物模型Id',
|
||||
format: 'uuid'
|
||||
},
|
||||
filedType: {
|
||||
ioTPlatformThingModelDataId: {
|
||||
type: 'string',
|
||||
description: '物联网平台中对应产品物模型属性或者事件类型 JiShe.ServicePro.Core.DataDictionaryTypeConst',
|
||||
nullable: true
|
||||
},
|
||||
ioTPlatformRawFieldName: {
|
||||
minLength: 1,
|
||||
type: 'string',
|
||||
description: '物联网平台中对应的产品物模型属性或者事件名称'
|
||||
},
|
||||
ioTPlatformRawFieldDataType: {
|
||||
minLength: 1,
|
||||
type: 'string',
|
||||
description: '物联网平台中对应的产品物模型属性或者事件数据类型,JiShe.ServicePro.Core.OneNETAllThingModel'
|
||||
},
|
||||
standardFieldName: {
|
||||
minLength: 1,
|
||||
type: 'string',
|
||||
description: '管理后台产品标准的物模型属性或者事件名称'
|
||||
},
|
||||
standardFieldValueType: {
|
||||
minLength: 1,
|
||||
type: 'string',
|
||||
description: '标准物模型字段值类型'
|
||||
},
|
||||
standardFieldDisplayName: {
|
||||
minLength: 1,
|
||||
type: 'string',
|
||||
description: '标准物模型字段显示名称'
|
||||
},
|
||||
isValueNeedConvert: {
|
||||
type: 'boolean',
|
||||
description: '是否需要值类型转换'
|
||||
description: '平台端物模型数据Id',
|
||||
format: 'uuid'
|
||||
},
|
||||
nativeSkipNumber: {
|
||||
type: 'integer',
|
||||
@ -3075,6 +3046,10 @@ export const DeviceThingModelPropertyUpdateInputSchema = {
|
||||
required: ['deviceThingModelId', 'id', 'ioTPlatformRawFieldDataType', 'ioTPlatformRawFieldName', 'nativeSkipNumber', 'nativeTakeNumber', 'parsingSequence', 'standardFieldDisplayName', 'standardFieldName', 'standardFieldValueType'],
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: {
|
||||
type: 'string',
|
||||
format: 'uuid'
|
||||
},
|
||||
deviceThingModelId: {
|
||||
type: 'string',
|
||||
description: '设备端物模型Id',
|
||||
@ -3138,10 +3113,6 @@ export const DeviceThingModelPropertyUpdateInputSchema = {
|
||||
description: '反转获取数量',
|
||||
format: 'int32',
|
||||
nullable: true
|
||||
},
|
||||
id: {
|
||||
type: 'string',
|
||||
format: 'uuid'
|
||||
}
|
||||
},
|
||||
additionalProperties: false,
|
||||
|
||||
@ -1572,33 +1572,9 @@ export type DeviceThingModelPropertyCreateInput = {
|
||||
*/
|
||||
deviceThingModelId: string;
|
||||
/**
|
||||
* 物联网平台中对应产品物模型属性或者事件类型 JiShe.ServicePro.Core.DataDictionaryTypeConst
|
||||
* 平台端物模型数据Id
|
||||
*/
|
||||
filedType?: (string) | null;
|
||||
/**
|
||||
* 物联网平台中对应的产品物模型属性或者事件名称
|
||||
*/
|
||||
ioTPlatformRawFieldName: string;
|
||||
/**
|
||||
* 物联网平台中对应的产品物模型属性或者事件数据类型,JiShe.ServicePro.Core.OneNETAllThingModel
|
||||
*/
|
||||
ioTPlatformRawFieldDataType: string;
|
||||
/**
|
||||
* 管理后台产品标准的物模型属性或者事件名称
|
||||
*/
|
||||
standardFieldName: string;
|
||||
/**
|
||||
* 标准物模型字段值类型
|
||||
*/
|
||||
standardFieldValueType: string;
|
||||
/**
|
||||
* 标准物模型字段显示名称
|
||||
*/
|
||||
standardFieldDisplayName: string;
|
||||
/**
|
||||
* 是否需要值类型转换
|
||||
*/
|
||||
isValueNeedConvert?: boolean;
|
||||
ioTPlatformThingModelDataId?: string;
|
||||
/**
|
||||
* 正序跳过数量
|
||||
*/
|
||||
@ -1771,6 +1747,7 @@ export type DeviceThingModelPropertyPageInput = {
|
||||
* 设备物模型属性更新输入
|
||||
*/
|
||||
export type DeviceThingModelPropertyUpdateInput = {
|
||||
id: string;
|
||||
/**
|
||||
* 设备端物模型Id
|
||||
*/
|
||||
@ -1820,7 +1797,6 @@ export type DeviceThingModelPropertyUpdateInput = {
|
||||
* 反转获取数量
|
||||
*/
|
||||
reversalTakeNumber?: (number) | null;
|
||||
id: string;
|
||||
};
|
||||
|
||||
export type DeviceThingModelUpdateInput = {
|
||||
|
||||
@ -0,0 +1,198 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, watch, computed, h } from 'vue';
|
||||
import { Select, Divider, Row } from 'ant-design-vue';
|
||||
import { ChevronLeft, ChevronRight } from '@vben/icons';
|
||||
import { postIoTplatformThingModelInfoPageAsync } from '#/api-client';
|
||||
import { $t } from '#/locales';
|
||||
import { useDebounceFn } from '@vueuse/core';
|
||||
|
||||
interface Props {
|
||||
value?: string;
|
||||
typeCode?: string | number | null;
|
||||
filedType?: string | null;
|
||||
ioTPlatform?: number | string | null;
|
||||
ioTPlatformProductId?: string | null;
|
||||
placeholder?: string;
|
||||
disabled?: boolean;
|
||||
allowClear?: boolean;
|
||||
onResolve?: (item: any | null) => void;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
placeholder: $t('common.pleaseSelect') + $t('abp.thingModelInfos.StandardFieldName'),
|
||||
disabled: false,
|
||||
allowClear: true,
|
||||
});
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:value': [string | undefined];
|
||||
change: [string | undefined];
|
||||
'item-change': [any | null];
|
||||
}>();
|
||||
|
||||
const VNodes = (props: any) => {
|
||||
return props.vnodes;
|
||||
};
|
||||
|
||||
const options = ref<any[]>([]);
|
||||
const total = ref(0);
|
||||
const loading = ref<boolean>(false);
|
||||
const query = ref({
|
||||
pageIndex: 1,
|
||||
pageSize: 10,
|
||||
filter: '',
|
||||
});
|
||||
|
||||
const maxPage = computed(() => Math.ceil((total.value || 0) / query.value.pageSize) || 1);
|
||||
|
||||
const fetchData = async () => {
|
||||
// 需要平台和产品ID才能获取数据
|
||||
if (!props.ioTPlatform || !props.ioTPlatformProductId) {
|
||||
options.value = [];
|
||||
total.value = 0;
|
||||
return;
|
||||
}
|
||||
loading.value = true;
|
||||
try {
|
||||
const requestBody: any = {
|
||||
pageIndex: query.value.pageIndex,
|
||||
pageSize: query.value.pageSize,
|
||||
...(query.value.filter && { searchKeyWords: query.value.filter }),
|
||||
...(props.ioTPlatform && {
|
||||
ioTPlatform:
|
||||
typeof props.ioTPlatform === 'string'
|
||||
? Number.parseInt(props.ioTPlatform)
|
||||
: props.ioTPlatform,
|
||||
}),
|
||||
...(props.ioTPlatformProductId && {
|
||||
ioTPlatformProductId: String(props.ioTPlatformProductId),
|
||||
}),
|
||||
...(props.filedType && { filedType: String(props.filedType) }),
|
||||
...(props.typeCode && !props.filedType && { filedType: String(props.typeCode) }),
|
||||
};
|
||||
|
||||
const { data } = await postIoTplatformThingModelInfoPageAsync({
|
||||
body: requestBody,
|
||||
});
|
||||
const items = Array.isArray(data?.items) ? data!.items : [];
|
||||
const mappedItems = items.map((item: any) => ({
|
||||
label: `${item.standardFieldDisplayName || item.ioTPlatformRawFieldName || item.id || ''}`,
|
||||
value: item.id || '',
|
||||
...item,
|
||||
}));
|
||||
|
||||
// 如果有当前值但不在当前页的选项中,需要添加当前值到选项中
|
||||
if (props.value && props.value.trim() !== '' && !mappedItems.find(item => item.value === props.value)) {
|
||||
// 如果当前值不在选项中,添加一个占位项
|
||||
mappedItems.unshift({
|
||||
label: `当前值: ${props.value}`,
|
||||
value: props.value,
|
||||
displayText: props.value,
|
||||
code: props.value,
|
||||
});
|
||||
}
|
||||
|
||||
options.value = mappedItems;
|
||||
total.value = (data as any)?.totalCount || 0;
|
||||
} catch (err) {
|
||||
console.error('获取标准物模型编码失败:', err);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const changePage = (next: number) => {
|
||||
if (next === 1) {
|
||||
if (query.value.pageIndex >= maxPage.value) return;
|
||||
query.value.pageIndex += 1;
|
||||
} else {
|
||||
if (query.value.pageIndex <= 1) return;
|
||||
query.value.pageIndex -= 1;
|
||||
}
|
||||
fetchData();
|
||||
};
|
||||
|
||||
const onSearch = useDebounceFn((kw: string) => {
|
||||
query.value.pageIndex = 1;
|
||||
query.value.filter = kw;
|
||||
fetchData();
|
||||
}, 400);
|
||||
|
||||
const onChange = (val?: string) => {
|
||||
emit('update:value', val);
|
||||
emit('change', val);
|
||||
if (val) {
|
||||
const found = options.value.find((o) => o.value === val) || null;
|
||||
emit('item-change', found);
|
||||
props.onResolve && props.onResolve(found);
|
||||
} else {
|
||||
emit('item-change', null);
|
||||
props.onResolve && props.onResolve(null);
|
||||
}
|
||||
};
|
||||
|
||||
watch(
|
||||
() => [props.filedType, props.typeCode, props.ioTPlatform, props.ioTPlatformProductId],
|
||||
() => {
|
||||
// reset when filedType/typeCode/platform/product changes
|
||||
query.value.pageIndex = 1;
|
||||
query.value.filter = '';
|
||||
options.value = [];
|
||||
total.value = 0;
|
||||
// 只要有平台和产品ID就可以获取数据,filedType/typeCode 是可选的
|
||||
if (props.ioTPlatform && props.ioTPlatformProductId) {
|
||||
fetchData();
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
// 监听初始值变化,确保编辑时能正确显示
|
||||
watch(
|
||||
() => props.value,
|
||||
(newValue) => {
|
||||
if (newValue && newValue.trim() !== '' && props.ioTPlatform && props.ioTPlatformProductId && !options.value.find(item => item.value === newValue)) {
|
||||
// 如果有值但不在当前选项中,重新获取数据
|
||||
fetchData();
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Select
|
||||
:value="value"
|
||||
:showSearch="true"
|
||||
:filter-option="false"
|
||||
:options="options"
|
||||
:placeholder="placeholder"
|
||||
:disabled="disabled"
|
||||
:allowClear="allowClear"
|
||||
:loading="loading"
|
||||
@search="onSearch"
|
||||
@change="onChange"
|
||||
>
|
||||
<template #dropdownRender="{ menuNode: menu }">
|
||||
<v-nodes :vnodes="menu" />
|
||||
<Divider style="margin: 4px 0" />
|
||||
<div @mousedown="(e) => e.preventDefault()">
|
||||
<Row type="flex" justify="space-around" align="middle">
|
||||
<ChevronLeft @click="changePage(0)" :class="{ 'text-gray-400': query.pageIndex <= 1 }"
|
||||
style="cursor: pointer; width: 16px; height: 16px;" />
|
||||
<div>{{ `${query.pageIndex}/${maxPage}` }}</div>
|
||||
<ChevronRight @click="changePage(1)" :class="{ 'text-gray-400': query.pageIndex >= maxPage }"
|
||||
style="cursor: pointer; width: 16px; height: 16px;" />
|
||||
</Row>
|
||||
</div>
|
||||
</template>
|
||||
</Select>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.text-gray-400 {
|
||||
color: #9ca3af;
|
||||
cursor: not-allowed !important;
|
||||
}
|
||||
</style>
|
||||
@ -22,6 +22,8 @@ import {
|
||||
import { TableAction } from '#/components/table-action';
|
||||
import { $t } from '#/locales';
|
||||
|
||||
import IoTPlatformThingModelDataSelect from '../IoTPlatformThingModelDataSelect.vue';
|
||||
|
||||
defineOptions({
|
||||
name: 'DeviceThingModelPropertyModal',
|
||||
});
|
||||
@ -155,13 +157,34 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
||||
},
|
||||
});
|
||||
|
||||
// 属性新增/编辑弹窗
|
||||
const [PropertyFormModal, propertyFormModalApi] = useVbenModal({
|
||||
// 属性新增弹窗(独立)
|
||||
const [AddPropertyFormModal, addPropertyFormModalApi] = useVbenModal({
|
||||
draggable: true,
|
||||
footer: true,
|
||||
showCancelButton: true,
|
||||
showConfirmButton: true,
|
||||
onConfirm: submitProperty,
|
||||
onConfirm: submitAddProperty,
|
||||
onBeforeClose: () => {
|
||||
return true;
|
||||
},
|
||||
onOpenChange: (isOpen: boolean) => {
|
||||
if (isOpen) {
|
||||
// 新增模式下,清空表单
|
||||
addPropertyFormApi.resetForm();
|
||||
}
|
||||
},
|
||||
onCancel: () => {
|
||||
addPropertyFormModalApi.close();
|
||||
},
|
||||
});
|
||||
|
||||
// 属性编辑弹窗(独立)
|
||||
const [EditPropertyFormModal, editPropertyFormModalApi] = useVbenModal({
|
||||
draggable: true,
|
||||
footer: true,
|
||||
showCancelButton: true,
|
||||
showConfirmButton: true,
|
||||
onConfirm: submitEditProperty,
|
||||
onBeforeClose: () => {
|
||||
return true;
|
||||
},
|
||||
@ -184,19 +207,16 @@ const [PropertyFormModal, propertyFormModalApi] = useVbenModal({
|
||||
// 如果后端返回的是数字,转换为字符串;如果已经是字符串,保持原样
|
||||
values.parsingSequence = String(values.parsingSequence);
|
||||
}
|
||||
propertyFormApi.setValues(values);
|
||||
editPropertyFormApi.setValues(values);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载属性详情失败:', error);
|
||||
}
|
||||
});
|
||||
} else if (isOpen) {
|
||||
// 新增模式下,清空表单
|
||||
propertyFormApi.resetForm();
|
||||
}
|
||||
},
|
||||
onCancel: () => {
|
||||
propertyFormModalApi.close();
|
||||
editPropertyFormModalApi.close();
|
||||
},
|
||||
});
|
||||
|
||||
@ -230,151 +250,273 @@ const [CopyDeviceThingModelModal, copyDeviceThingModelModalApi] = useVbenModal({
|
||||
},
|
||||
});
|
||||
|
||||
// 属性表单 schema
|
||||
const propertyFormSchema = computed(() => {
|
||||
const isEdit = !!editRow.value.id;
|
||||
// 新增属性表单 schema(只包含新增接口需要的字段)
|
||||
const addPropertyFormSchema = computed(() => [
|
||||
{
|
||||
component: 'ApiSelect',
|
||||
fieldName: 'filedType',
|
||||
label: '物模型类型',
|
||||
componentProps: {
|
||||
api: getCommonGetSelectList,
|
||||
params: {
|
||||
query: {
|
||||
typeName: 'DataDictionaryTypeConst',
|
||||
},
|
||||
},
|
||||
labelField: 'value',
|
||||
valueField: 'key',
|
||||
optionsPropName: 'options',
|
||||
immediate: true,
|
||||
allowClear: true,
|
||||
placeholder: '请选择物模型类型',
|
||||
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 [];
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
component: IoTPlatformThingModelDataSelect,
|
||||
fieldName: 'ioTPlatformThingModelDataId',
|
||||
label: '平台端物模型数据选择',
|
||||
modelPropName: 'value',
|
||||
dependencies: {
|
||||
triggerFields: ['filedType'],
|
||||
},
|
||||
componentProps: (formValues: any) => ({
|
||||
filedType: formValues?.filedType || null,
|
||||
ioTPlatform: ioTPlatform.value,
|
||||
ioTPlatformProductId: ioTPlatformProductId.value,
|
||||
placeholder: '请选择平台端物模型数据',
|
||||
}),
|
||||
},
|
||||
{
|
||||
component: 'ApiSelect',
|
||||
fieldName: 'parsingSequence',
|
||||
label: '解析方式',
|
||||
rules: z.preprocess(
|
||||
(v) => (v == null ? '' : v),
|
||||
z.string().min(1, $t('common.required')),
|
||||
),
|
||||
componentProps: {
|
||||
api: getCommonGetSelectList,
|
||||
params: {
|
||||
query: {
|
||||
typeName: 'ParsingSequenceTypeEnum',
|
||||
},
|
||||
},
|
||||
labelField: 'value',
|
||||
valueField: 'key',
|
||||
optionsPropName: 'options',
|
||||
immediate: true,
|
||||
allowClear: true,
|
||||
placeholder: `${$t('common.pleaseSelect')}解析方式`,
|
||||
afterFetch: (res: any) => {
|
||||
let items = [];
|
||||
if (Array.isArray(res)) {
|
||||
items = res;
|
||||
} else if (res && Array.isArray(res.items)) {
|
||||
items = res.items;
|
||||
} else if (res && Array.isArray(res.data)) {
|
||||
items = res.data;
|
||||
}
|
||||
// 将 key 转换为字符串,因为表单需要字符串类型
|
||||
return items.map((item: any) => ({
|
||||
...item,
|
||||
key: String(item.key || item.value),
|
||||
}));
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
component: 'InputNumber',
|
||||
fieldName: 'nativeSkipNumber',
|
||||
label: '正序跳过数量',
|
||||
rules: z.preprocess(
|
||||
(v) => (v == null ? 0 : v),
|
||||
z.number().min(0, '正序跳过数量不能小于0'),
|
||||
),
|
||||
componentProps: {
|
||||
min: 0,
|
||||
placeholder: `${$t('common.pleaseInput')}正序跳过数量`,
|
||||
},
|
||||
},
|
||||
{
|
||||
component: 'InputNumber',
|
||||
fieldName: 'nativeTakeNumber',
|
||||
label: '正序获取数量',
|
||||
rules: z.preprocess(
|
||||
(v) => (v == null ? 0 : v),
|
||||
z.number().min(0, '正序获取数量不能小于0'),
|
||||
),
|
||||
componentProps: {
|
||||
min: 0,
|
||||
placeholder: `${$t('common.pleaseInput')}正序获取数量`,
|
||||
},
|
||||
},
|
||||
{
|
||||
component: 'InputNumber',
|
||||
fieldName: 'reversalSkipNumber',
|
||||
label: '反转跳过数量',
|
||||
componentProps: {
|
||||
min: 0,
|
||||
placeholder: `${$t('common.pleaseInput')}反转跳过数量`,
|
||||
},
|
||||
},
|
||||
{
|
||||
component: 'InputNumber',
|
||||
fieldName: 'reversalTakeNumber',
|
||||
label: '反转获取数量',
|
||||
componentProps: {
|
||||
min: 0,
|
||||
placeholder: `${$t('common.pleaseInput')}反转获取数量`,
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
// 编辑属性表单 schema(包含编辑接口需要的所有字段)
|
||||
const editPropertyFormSchema = computed(() => {
|
||||
return [
|
||||
{
|
||||
component: 'Input',
|
||||
fieldName: 'standardFieldDisplayName',
|
||||
label: '标准属性名称',
|
||||
rules: z.preprocess(
|
||||
(v) => (v == null ? '' : v),
|
||||
z.string().min(1, $t('common.required')),
|
||||
),
|
||||
componentProps: {
|
||||
placeholder: `${$t('common.pleaseInput')}标准属性名称`,
|
||||
disabled: isEdit, // 编辑模式下禁用
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
fieldName: 'standardFieldDisplayName',
|
||||
label: '标准属性名称',
|
||||
rules: z.preprocess(
|
||||
(v) => (v == null ? '' : v),
|
||||
z.string().min(1, $t('common.required')),
|
||||
),
|
||||
componentProps: {
|
||||
placeholder: `${$t('common.pleaseInput')}标准属性名称`,
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
fieldName: 'standardFieldName',
|
||||
label: '标准属性标识符',
|
||||
rules: z.preprocess(
|
||||
(v) => (v == null ? '' : v),
|
||||
z.string().min(1, $t('common.required')),
|
||||
),
|
||||
componentProps: {
|
||||
placeholder: `${$t('common.pleaseInput')}标准属性标识符`,
|
||||
disabled: isEdit, // 编辑模式下禁用
|
||||
},
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
fieldName: 'standardFieldName',
|
||||
label: '标准属性标识符',
|
||||
rules: z.preprocess(
|
||||
(v) => (v == null ? '' : v),
|
||||
z.string().min(1, $t('common.required')),
|
||||
),
|
||||
componentProps: {
|
||||
placeholder: `${$t('common.pleaseInput')}标准属性标识符`,
|
||||
},
|
||||
{
|
||||
component: 'ApiSelect',
|
||||
fieldName: 'standardFieldValueType',
|
||||
label: '标准属性值类型',
|
||||
rules: z.preprocess(
|
||||
(v) => (v == null ? '' : v),
|
||||
z.string().min(1, $t('common.required')),
|
||||
),
|
||||
componentProps: {
|
||||
api: getCommonGetSelectList,
|
||||
params: {
|
||||
query: {
|
||||
typeName: 'StandardThingModelDataTypeEnum',
|
||||
},
|
||||
},
|
||||
labelField: 'value',
|
||||
valueField: 'secondValue',
|
||||
optionsPropName: 'options',
|
||||
immediate: true,
|
||||
allowClear: true,
|
||||
disabled: isEdit, // 编辑模式下禁用
|
||||
placeholder: `${$t('common.pleaseSelect')}标准属性值类型`,
|
||||
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 [];
|
||||
},
|
||||
{
|
||||
component: 'ApiSelect',
|
||||
fieldName: 'standardFieldValueType',
|
||||
label: '标准属性值类型',
|
||||
rules: z.preprocess(
|
||||
(v) => (v == null ? '' : v),
|
||||
z.string().min(1, $t('common.required')),
|
||||
),
|
||||
componentProps: {
|
||||
api: getCommonGetSelectList,
|
||||
params: {
|
||||
query: {
|
||||
typeName: 'StandardThingModelDataTypeEnum',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
fieldName: 'ioTPlatformRawFieldName',
|
||||
label: '平台属性标识符',
|
||||
rules: z.preprocess(
|
||||
(v) => (v == null ? '' : v),
|
||||
z.string().min(1, $t('common.required')),
|
||||
),
|
||||
componentProps: {
|
||||
placeholder: `${$t('common.pleaseInput')}平台属性标识符`,
|
||||
labelField: 'value',
|
||||
valueField: 'secondValue',
|
||||
optionsPropName: 'options',
|
||||
immediate: true,
|
||||
allowClear: true,
|
||||
placeholder: `${$t('common.pleaseSelect')}标准属性值类型`,
|
||||
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 [];
|
||||
},
|
||||
},
|
||||
{
|
||||
component: 'ApiSelect',
|
||||
fieldName: 'ioTPlatformRawFieldDataType',
|
||||
label: '平台属性值类型',
|
||||
rules: z.preprocess(
|
||||
(v) => (v == null ? '' : v),
|
||||
z.string().min(1, $t('common.required')),
|
||||
),
|
||||
componentProps: {
|
||||
api: getCommonGetSelectList,
|
||||
params: {
|
||||
query: {
|
||||
typeName: 'StandardThingModelDataTypeEnum',
|
||||
},
|
||||
},
|
||||
labelField: 'value',
|
||||
valueField: 'secondValue',
|
||||
optionsPropName: 'options',
|
||||
immediate: true,
|
||||
allowClear: true,
|
||||
placeholder: `${$t('common.pleaseSelect')}平台属性值类型`,
|
||||
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 [];
|
||||
},
|
||||
{
|
||||
component: 'Input',
|
||||
fieldName: 'ioTPlatformRawFieldName',
|
||||
label: '平台属性标识符',
|
||||
rules: z.preprocess(
|
||||
(v) => (v == null ? '' : v),
|
||||
z.string().min(1, $t('common.required')),
|
||||
),
|
||||
componentProps: {
|
||||
placeholder: `${$t('common.pleaseInput')}平台属性标识符`,
|
||||
},
|
||||
},
|
||||
{
|
||||
component: 'ApiSelect',
|
||||
fieldName: 'ioTPlatformRawFieldDataType',
|
||||
label: '平台属性值类型',
|
||||
rules: z.preprocess(
|
||||
(v) => (v == null ? '' : v),
|
||||
z.string().min(1, $t('common.required')),
|
||||
),
|
||||
componentProps: {
|
||||
api: getCommonGetSelectList,
|
||||
params: {
|
||||
query: {
|
||||
typeName: 'StandardThingModelDataTypeEnum',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
component: 'Switch',
|
||||
fieldName: 'isValueNeedConvert',
|
||||
label: '值类型是否转换',
|
||||
componentProps: {
|
||||
checkedChildren: '是',
|
||||
unCheckedChildren: '否',
|
||||
style: { width: 'auto' }, // 优化宽度显示
|
||||
labelField: 'value',
|
||||
valueField: 'secondValue',
|
||||
optionsPropName: 'options',
|
||||
immediate: true,
|
||||
allowClear: true,
|
||||
placeholder: `${$t('common.pleaseSelect')}平台属性值类型`,
|
||||
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 [];
|
||||
},
|
||||
},
|
||||
{
|
||||
component: 'ApiSelect',
|
||||
fieldName: 'parsingSequence',
|
||||
label: '解析方式',
|
||||
componentProps: {
|
||||
api: getCommonGetSelectList,
|
||||
params: {
|
||||
query: {
|
||||
typeName: 'ParsingSequenceTypeEnum',
|
||||
},
|
||||
},
|
||||
labelField: 'value',
|
||||
valueField: 'key',
|
||||
optionsPropName: 'options',
|
||||
immediate: true,
|
||||
allowClear: true,
|
||||
placeholder: `${$t('common.pleaseSelect')}解析方式`,
|
||||
afterFetch: (res: any) => {
|
||||
let items = [];
|
||||
if (Array.isArray(res)) {
|
||||
items = res;
|
||||
} else if (res && Array.isArray(res.items)) {
|
||||
items = res.items;
|
||||
} else if (res && Array.isArray(res.data)) {
|
||||
items = res.data;
|
||||
}
|
||||
// 将 key 转换为字符串,因为表单需要字符串类型
|
||||
return items.map((item: any) => ({
|
||||
...item,
|
||||
key: String(item.key || item.value),
|
||||
}));
|
||||
},
|
||||
{
|
||||
component: 'Switch',
|
||||
fieldName: 'isValueNeedConvert',
|
||||
label: '值类型是否转换',
|
||||
componentProps: {
|
||||
checkedChildren: '是',
|
||||
unCheckedChildren: '否',
|
||||
style: { width: 'auto' }, // 优化宽度显示
|
||||
},
|
||||
},
|
||||
{
|
||||
component: 'ApiSelect',
|
||||
fieldName: 'parsingSequence',
|
||||
label: '解析方式',
|
||||
componentProps: {
|
||||
api: getCommonGetSelectList,
|
||||
params: {
|
||||
query: {
|
||||
typeName: 'ParsingSequenceTypeEnum',
|
||||
},
|
||||
},
|
||||
labelField: 'value',
|
||||
valueField: 'key',
|
||||
optionsPropName: 'options',
|
||||
immediate: true,
|
||||
allowClear: true,
|
||||
placeholder: `${$t('common.pleaseSelect')}解析方式`,
|
||||
afterFetch: (res: any) => {
|
||||
let items = [];
|
||||
if (Array.isArray(res)) {
|
||||
items = res;
|
||||
} else if (res && Array.isArray(res.items)) {
|
||||
items = res.items;
|
||||
} else if (res && Array.isArray(res.data)) {
|
||||
items = res.data;
|
||||
}
|
||||
// 将 key 转换为字符串,因为表单需要字符串类型
|
||||
return items.map((item: any) => ({
|
||||
...item,
|
||||
key: String(item.key || item.value),
|
||||
}));
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
component: 'InputNumber',
|
||||
fieldName: 'nativeSkipNumber',
|
||||
@ -414,8 +556,8 @@ const propertyFormSchema = computed(() => {
|
||||
];
|
||||
});
|
||||
|
||||
// 属性表单
|
||||
const [PropertyForm, propertyFormApi] = useVbenForm({
|
||||
// 新增属性表单
|
||||
const [AddPropertyForm, addPropertyFormApi] = useVbenForm({
|
||||
collapsed: false,
|
||||
commonConfig: {
|
||||
labelWidth: 140,
|
||||
@ -424,18 +566,34 @@ const [PropertyForm, propertyFormApi] = useVbenForm({
|
||||
},
|
||||
},
|
||||
layout: 'horizontal',
|
||||
schema: propertyFormSchema.value,
|
||||
schema: addPropertyFormSchema,
|
||||
showCollapseButton: false,
|
||||
showDefaultActions: false,
|
||||
wrapperClass: 'grid-cols-2',
|
||||
});
|
||||
|
||||
// 监听 editRow 变化,动态更新 schema
|
||||
// 编辑属性表单
|
||||
const [EditPropertyForm, editPropertyFormApi] = useVbenForm({
|
||||
collapsed: false,
|
||||
commonConfig: {
|
||||
labelWidth: 140,
|
||||
componentProps: {
|
||||
class: 'w-4/5',
|
||||
},
|
||||
},
|
||||
layout: 'horizontal',
|
||||
schema: editPropertyFormSchema.value,
|
||||
showCollapseButton: false,
|
||||
showDefaultActions: false,
|
||||
wrapperClass: 'grid-cols-2',
|
||||
});
|
||||
|
||||
// 监听 editRow 变化,动态更新编辑表单 schema
|
||||
watch(
|
||||
() => editRow.value.id,
|
||||
() => {
|
||||
if (propertyFormApi && propertyFormApi.updateSchema) {
|
||||
propertyFormApi.updateSchema(propertyFormSchema.value);
|
||||
if (editPropertyFormApi && editPropertyFormApi.updateSchema) {
|
||||
editPropertyFormApi.updateSchema(editPropertyFormSchema.value);
|
||||
}
|
||||
},
|
||||
);
|
||||
@ -588,14 +746,13 @@ const [CopyDeviceThingModelForm, copyDeviceThingModelFormApi] = useVbenForm({
|
||||
|
||||
// 打开新增属性弹窗
|
||||
function openAddPropertyModal() {
|
||||
editRow.value = {};
|
||||
propertyFormModalApi.open();
|
||||
addPropertyFormModalApi.open();
|
||||
}
|
||||
|
||||
// 打开编辑属性弹窗
|
||||
function openEditPropertyModal(record: any) {
|
||||
editRow.value = record;
|
||||
propertyFormModalApi.open();
|
||||
editPropertyFormModalApi.open();
|
||||
}
|
||||
|
||||
// 打开快速复制平台端物模型弹窗
|
||||
@ -610,44 +767,105 @@ function openCopyDeviceThingModelModal() {
|
||||
copyDeviceThingModelModalApi.open();
|
||||
}
|
||||
|
||||
// 提交属性(新增/编辑)
|
||||
async function submitProperty() {
|
||||
const isEdit = !!editRow.value.id;
|
||||
const { valid } = await propertyFormApi.validate();
|
||||
// 提交新增属性
|
||||
async function submitAddProperty() {
|
||||
const { valid } = await addPropertyFormApi.validate();
|
||||
if (!valid) return;
|
||||
|
||||
const formValues = await propertyFormApi.getValues();
|
||||
const formValues = await addPropertyFormApi.getValues();
|
||||
const fetchParams: any = {
|
||||
...formValues,
|
||||
deviceThingModelId: deviceThingModelId.value,
|
||||
...(formValues.parsingSequence && {
|
||||
// 解析方式从字符串转换为数字
|
||||
parsingSequence: Number.parseInt(String(formValues.parsingSequence)),
|
||||
...(formValues.ioTPlatformThingModelDataId && {
|
||||
ioTPlatformThingModelDataId: String(
|
||||
formValues.ioTPlatformThingModelDataId,
|
||||
),
|
||||
}),
|
||||
nativeSkipNumber: formValues.nativeSkipNumber || 0,
|
||||
nativeTakeNumber: formValues.nativeTakeNumber || 0,
|
||||
parsingSequence:
|
||||
typeof formValues.parsingSequence === 'string'
|
||||
? Number.parseInt(formValues.parsingSequence)
|
||||
: formValues.parsingSequence,
|
||||
...(formValues.reversalSkipNumber !== undefined &&
|
||||
formValues.reversalSkipNumber !== null && {
|
||||
reversalSkipNumber: formValues.reversalSkipNumber,
|
||||
}),
|
||||
...(formValues.reversalTakeNumber !== undefined &&
|
||||
formValues.reversalTakeNumber !== null && {
|
||||
reversalTakeNumber: formValues.reversalTakeNumber,
|
||||
}),
|
||||
...(isEdit && { id: editRow.value.id }),
|
||||
};
|
||||
|
||||
try {
|
||||
const api = isEdit
|
||||
? postDeviceThingModelManagementPropertyUpdateAsync
|
||||
: postDeviceThingModelManagementPropertyCreateAsync;
|
||||
const resp = await api({ body: fetchParams });
|
||||
const resp = await postDeviceThingModelManagementPropertyCreateAsync({
|
||||
body: fetchParams,
|
||||
});
|
||||
if (resp.data) {
|
||||
Message.success(
|
||||
isEdit ? $t('common.editSuccess') : $t('common.addSuccess'),
|
||||
);
|
||||
propertyFormModalApi.close();
|
||||
Message.success($t('common.addSuccess'));
|
||||
addPropertyFormModalApi.close();
|
||||
await nextTick();
|
||||
if (gridApi && gridApi.reload) {
|
||||
await gridApi.reload();
|
||||
}
|
||||
} else {
|
||||
Message.error($t('common.addFail'));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('提交属性失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// 提交编辑属性
|
||||
async function submitEditProperty() {
|
||||
const { valid } = await editPropertyFormApi.validate();
|
||||
if (!valid) return;
|
||||
|
||||
const formValues = await editPropertyFormApi.getValues();
|
||||
const fetchParams: any = {
|
||||
id: editRow.value.id,
|
||||
deviceThingModelId: deviceThingModelId.value,
|
||||
...(formValues.filedType && { filedType: formValues.filedType }),
|
||||
ioTPlatformRawFieldName: formValues.ioTPlatformRawFieldName,
|
||||
ioTPlatformRawFieldDataType: formValues.ioTPlatformRawFieldDataType,
|
||||
standardFieldName: formValues.standardFieldName,
|
||||
standardFieldValueType: formValues.standardFieldValueType,
|
||||
standardFieldDisplayName: formValues.standardFieldDisplayName,
|
||||
...(formValues.isValueNeedConvert !== undefined && {
|
||||
isValueNeedConvert: formValues.isValueNeedConvert,
|
||||
}),
|
||||
nativeSkipNumber: formValues.nativeSkipNumber || 0,
|
||||
nativeTakeNumber: formValues.nativeTakeNumber || 0,
|
||||
parsingSequence:
|
||||
typeof formValues.parsingSequence === 'string'
|
||||
? Number.parseInt(formValues.parsingSequence)
|
||||
: formValues.parsingSequence,
|
||||
...(formValues.reversalSkipNumber !== undefined &&
|
||||
formValues.reversalSkipNumber !== null && {
|
||||
reversalSkipNumber: formValues.reversalSkipNumber,
|
||||
}),
|
||||
...(formValues.reversalTakeNumber !== undefined &&
|
||||
formValues.reversalTakeNumber !== null && {
|
||||
reversalTakeNumber: formValues.reversalTakeNumber,
|
||||
}),
|
||||
};
|
||||
|
||||
try {
|
||||
const resp = await postDeviceThingModelManagementPropertyUpdateAsync({
|
||||
body: fetchParams,
|
||||
});
|
||||
if (resp.data) {
|
||||
Message.success($t('common.editSuccess'));
|
||||
editPropertyFormModalApi.close();
|
||||
editRow.value = {};
|
||||
await nextTick();
|
||||
if (gridApi && gridApi.reload) {
|
||||
await gridApi.reload();
|
||||
}
|
||||
} else {
|
||||
Message.error(isEdit ? $t('common.editFail') : $t('common.addFail'));
|
||||
Message.error($t('common.editFail'));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('提交属性失败:', error);
|
||||
Message.error(isEdit ? $t('common.editFail') : $t('common.addFail'));
|
||||
}
|
||||
}
|
||||
|
||||
@ -685,7 +903,6 @@ async function submitCopyDeviceThingModel() {
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('快速复制设备端物模型属性失败:', error);
|
||||
Message.error('快速复制设备端物模型属性失败');
|
||||
}
|
||||
}
|
||||
|
||||
@ -727,7 +944,6 @@ async function submitCopyProperty() {
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('快速复制平台端物模型属性失败:', error);
|
||||
Message.error('快速复制平台端物模型属性失败');
|
||||
}
|
||||
}
|
||||
|
||||
@ -748,7 +964,6 @@ async function onDeleteProperty(record: any) {
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('删除属性失败:', error);
|
||||
Message.error($t('common.deleteFail'));
|
||||
}
|
||||
}
|
||||
|
||||
@ -824,10 +1039,15 @@ const [Modal, modalApi] = useVbenModal({
|
||||
</template>
|
||||
</Grid>
|
||||
|
||||
<!-- 属性新增/编辑弹窗 -->
|
||||
<PropertyFormModal :title="editRow.id ? $t('common.edit') : $t('common.add')" class="w-[900px]">
|
||||
<PropertyForm />
|
||||
</PropertyFormModal>
|
||||
<!-- 属性新增弹窗 -->
|
||||
<AddPropertyFormModal :title="$t('common.add')" class="w-[900px]">
|
||||
<AddPropertyForm />
|
||||
</AddPropertyFormModal>
|
||||
|
||||
<!-- 属性编辑弹窗 -->
|
||||
<EditPropertyFormModal :title="$t('common.edit')" class="w-[900px]">
|
||||
<EditPropertyForm />
|
||||
</EditPropertyFormModal>
|
||||
|
||||
<!-- 快速复制平台端物模型属性弹窗 -->
|
||||
<CopyPropertyModal title="快速复制平台端物模型属性" class="w-[600px]">
|
||||
@ -835,10 +1055,7 @@ const [Modal, modalApi] = useVbenModal({
|
||||
</CopyPropertyModal>
|
||||
|
||||
<!-- 快速复制设备端物模型属性弹窗 -->
|
||||
<CopyDeviceThingModelModal
|
||||
title="快速复制设备端物模型属性"
|
||||
class="w-[600px]"
|
||||
>
|
||||
<CopyDeviceThingModelModal title="快速复制设备端物模型属性" class="w-[600px]">
|
||||
<CopyDeviceThingModelForm />
|
||||
</CopyDeviceThingModelModal>
|
||||
</Modal>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user