fix: 优化物模型-标签定义

This commit is contained in:
XieYongHong 2023-07-08 18:13:47 +08:00
parent 3231c7ea12
commit c8fa001655
21 changed files with 742 additions and 390 deletions

View File

@ -10,6 +10,7 @@ export type DeviceInstance = {
protocolName: string;
security: any;
deriveMetadata: string;
productMetadata: string;
metadata: string;
binds: any;
state: {

View File

@ -331,8 +331,9 @@ const submitData = () => {
form.classifiedName
? form.classifiedName
: (form.classifiedName = '');
const res = await editProduct(form);
loading.value = false
const res = await editProduct(form).finally(() => {
loading.value = false
});
if (res.status === 200) {
message.success('保存成功!');
emit('success');

View File

@ -12,10 +12,10 @@
<template #expand>
<PermissionButton
type="primary"
v-if="!dataSource.length"
v-if="!showSave"
:hasPermission="`${permission}:update`"
key="add"
@click="handleAddClick()"
:disabled="hasOperate('add', type)"
:tooltip="{
placement: hasOperate('add', type) ? 'topRight' : 'top',
@ -23,6 +23,7 @@
? '当前的存储方式不支持新增'
: '新增',
}"
@click="handleAddClick()"
>
新增
</PermissionButton>
@ -31,7 +32,8 @@
:hasPermission="`${permission}:update`"
key="update"
v-else
@click="handleSaveClick"
:loading="loading"
:disabled="hasOperate('add', type)"
:tooltip="{
title: hasOperate('add', type)
@ -39,6 +41,7 @@
: '保存',
placement: hasOperate('add', type) ? 'topRight' : 'top',
}"
@click="handleSaveClick"
>
保存
</PermissionButton>
@ -89,7 +92,7 @@
{{ sourceMap?.[data.record?.expands?.source] || '' }}
</template>
<template #inputs="{ data }">
<InputParams v-model:value="data.record" />
<InputParams v-model:value="data.record.inputs" />
</template>
<template #output="{ data }">
{{ data.record.output?.type }}
@ -101,7 +104,7 @@
{{ levelMap?.[data.record.expands?.level] || '-' }}
</template>
<template #properties="{ data }">
<ConfigParams v-model:value="data.record" />
<ConfigParams v-model:value="data.record.valueType" />
</template>
<template #outInput>
object
@ -112,7 +115,7 @@
</j-tag>
</template>
<template #other="{ data }">
<OtherSetting v-model:value="data.record" />
<OtherSetting v-model:value="data.record.expands" :type="data.record.valueType.type" />
</template>
<template #action="{data}">
<j-space>
@ -143,7 +146,6 @@
<AIcon type="PlusSquareOutlined" />
</PermissionButton>
<PermissionButton
v-if="type !== 'tags'"
:has-permission="true"
type="link"
key="edit"
@ -163,9 +165,9 @@
danger
:pop-confirm="{
placement: 'topRight',
title: dataSource.length === 1 ? '这是最后一条数据了,确认删除?' : '确认删除?',
title: showSave ? '这是最后一条数据了,确认删除?' : '确认删除?',
onConfirm: async () => {
await removeItem(data.index, dataSource.length === 1);
await removeItem(data.index, showSave);
},
}"
:tooltip="{
@ -192,6 +194,11 @@
:data="detailData.data"
@cancel="cancelDetailModal"
/>
<TagsModal
v-else-if="type === 'tags' && detailData.visible"
:data="detailData.data"
@cancel="cancelDetailModal"
/>
</template>
<script setup lang="ts" name="BaseMetadata">
@ -216,13 +223,13 @@ import { DeviceInstance } from '@/views/device/Instance/typings';
import { onlyMessage } from '@/utils/comm';
import {omit} from "lodash-es";
import {useAction} from "@/views/device/components/Metadata/Base/hooks/useAction";
import { PropertiesModal, FunctionModal, EventModal } from './DetailModal'
import { PropertiesModal, FunctionModal, EventModal, TagsModal } from './DetailModal'
const props = defineProps({
// target: {
// type: String as PropType<'device' | 'product'>,
// default: 'product',
// },
target: {
type: String as PropType<'device' | 'product'>,
default: 'product',
},
type: {
type: String as PropType<MetadataType>,
default: undefined,
@ -233,10 +240,10 @@ const props = defineProps({
},
});
const target = inject<'device' | 'product'>('_metadataType', 'product');
const _target = inject<'device' | 'product'>('_metadataType', props.target);
const { data: metadata, noEdit } = useMetadata(target, props.type);
const { hasOperate } = useOperateLimits(target);
const { data: metadata, noEdit } = useMetadata(_target, props.type);
const { hasOperate } = useOperateLimits(_target);
const metadataStore = useMetadataStore()
const instanceStore = useInstanceStore()
@ -244,14 +251,18 @@ const productStore = useProductStore()
const dataSource = ref<MetadataItem[]>(metadata.value || []);
const tableRef = ref();
const loading = ref(false)
// const columns = computed(() => MetadataMapping.get(props.type!));
const {columns} = useColumns(props.type, target, noEdit)
const {columns} = useColumns(props.type, _target, noEdit)
const detailData = reactive({
data: {},
visible:false
})
const showSave = ref(!!metadata.value.length)
const { addAction, copyAction, removeAction } = useAction(tableRef)
provide('_dataSource', dataSource.value)
@ -268,7 +279,7 @@ const cancelDetailModal = () => {
const operateLimits = (action: 'add' | 'updata', types: MetadataType) => {
return (
target === 'device' &&
_target === 'device' &&
(instanceStore.detail.features || []).find((item: { id: string; name: string }) => item.id === limitsMap.get(`${types}-${action}`))
);
};
@ -339,21 +350,23 @@ const handleAddClick = async (_data?: any, index?: number) => {
const data = [...dataSource.value];
if (index !== undefined) {
//
const _data = await tableRef.value.getData()
console.log(_data)
if (_data) {
data.splice(index + 1, 0, newObject);
}
} else {
data.push(newObject);
}
dataSource.value = data
const _index = index !== undefined ? index + 1 : 0
tableRef.value?.addItemAll?.(_index)
// const data = [...dataSource.value];
//
// if (index !== undefined) {
// //
// const _data = await tableRef.value.getData()
// console.log(_data)
// if (_data) {
// data.splice(index + 1, 0, newObject);
// }
// } else {
// data.push(newObject);
// }
// dataSource.value = data
tableRef.value.addItem(newObject, index)
showSave.value = true
// const _index = index !== undefined ? index + 1 : 0
// tableRef.value?.addItemAll?.(_index)
};
const copyItem = (record: any, index: number) => {
@ -363,9 +376,13 @@ const copyItem = (record: any, index: number) => {
}
const removeItem = (index: number, isSave: false) => {
const data = [...dataSource.value];
data.splice(index, 1);
dataSource.value = data
// const data = [...dataSource.value];
// data.splice(index, 1);
// dataSource.value = data
const _data = tableRef.value.removeItem(index)
if (_data.length === 0) {
showSave.value = false
}
if (isSave) {
handleSaveClick()
}
@ -399,7 +416,7 @@ const handleSaveClick = async () => {
//
if(virtual.length) {
let res = undefined
if(target === 'device') {
if(_target === 'device') {
res = await saveDeviceVirtualProperty(instanceStore.current.productId, instanceStore.current.id, virtual)
} else {
res = await saveProductVirtualProperty(productStore.current.id, virtual)
@ -407,7 +424,7 @@ const handleSaveClick = async () => {
}
//
const updateStore = (metadata: string) => {
if (target === 'device') {
if (_target === 'device') {
const detail = instanceStore.current
detail.metadata = metadata
instanceStore.setCurrent(detail)
@ -417,10 +434,12 @@ const handleSaveClick = async () => {
productStore.setCurrent(detail)
}
}
const _detail: ProductItem | DeviceInstance = target === 'device' ? instanceStore.detail : productStore.current
const _detail: ProductItem | DeviceInstance = _target === 'device' ? instanceStore.detail : productStore.current
let _data = updateMetadata(props.type!, arr, _detail, updateStore)
const result = await asyncUpdateMetadata(target, _data)
loading.value = true
const result = await asyncUpdateMetadata(_target, _data).finally(() => {
loading.value = false
})
if(result.success) {
dataSource.value = resp
onlyMessage('操作成功!')

View File

@ -1,6 +1,7 @@
<template>
<j-modal
visible
:maskClosable="false"
title="事件详情"
width="650px"
@cancel="cancel"

View File

@ -3,6 +3,7 @@
visible
title="功能详情"
width="650px"
:maskClosable="false"
@cancel="cancel"
@ok="ok"
>

View File

@ -1,6 +1,7 @@
<template>
<j-modal
visible
:maskClosable="false"
title="属性详情"
@cancel="cancel"
@ok="ok"
@ -15,7 +16,7 @@
>
<a-descriptions-item label="属性标识">{{ data.id }}</a-descriptions-item>
<a-descriptions-item label="属性名称">{{ data.name }}</a-descriptions-item>
<a-descriptions-item label="属性类型">{{ data.valueType.type }}</a-descriptions-item>
<a-descriptions-item label="属性类型">{{ TypeStringMap[data.valueType.type] }}</a-descriptions-item>
<a-descriptions-item v-if="['int', 'long', 'float', 'double'].includes(data.valueType.type)" label="单位">{{ unitLabel }}</a-descriptions-item>
<a-descriptions-item v-if="['float', 'double'].includes(data.valueType.type)" label="精度">{{ data.valueType?.scale }}</a-descriptions-item>
<a-descriptions-item v-if="['string', 'password'].includes(data.valueType.type)" label="最大长度">{{ data.valueType?.maxLength }}</a-descriptions-item>
@ -40,7 +41,11 @@
:pagination="false"
size="small"
>
<template #bodyCell="{column, record}">
<span v-if="column.dataIndex === 'value'">
{{ record.range === 'true' ? record.value?.join('-') : record.value }}
</span>
</template>
</j-table>
</a-descriptions-item>
</j-descriptions>
@ -56,6 +61,7 @@ import {omit} from "lodash-es";
import {watch} from "vue";
import JsonView from './JsonView.vue'
import {getUnit} from "@/api/device/instance";
import {TypeStringMap} from "@/views/device/components/Metadata/Base/columns";
const props = defineProps({
data: {
@ -93,7 +99,7 @@ const metrics = reactive<{ columns: any[], dataSource: any }>({
columns: [
{ title: '指标标识', dataIndex: 'id' },
{ title: '指标名称', dataIndex: 'name' },
{ title: '指标', dataIndex: 'value' },
{ title: '指标', dataIndex: 'value' },
],
dataSource: []
})

View File

@ -0,0 +1,151 @@
<template>
<j-modal
visible
:maskClosable="false"
title="标签详情"
@cancel="cancel"
@ok="ok"
>
<j-descriptions
:column="1"
:labelStyle="{
width: '72px',
textAlign: 'right',
justifyContent: 'end'
}"
>
<a-descriptions-item label="标签标识">{{ data.id }}</a-descriptions-item>
<a-descriptions-item label="标签名称">{{ data.name }}</a-descriptions-item>
<a-descriptions-item label="标签类型">{{ data.valueType.type }}</a-descriptions-item>
<a-descriptions-item v-if="['int', 'long', 'float', 'double'].includes(data.valueType.type)" label="单位">{{ unitLabel }}</a-descriptions-item>
<a-descriptions-item v-if="['float', 'double'].includes(data.valueType.type)" label="精度">{{ data.valueType?.scale }}</a-descriptions-item>
<a-descriptions-item v-if="['string', 'password'].includes(data.valueType.type)" label="最大长度">{{ data.valueType?.maxLength }}</a-descriptions-item>
<a-descriptions-item v-if="data.valueType.type === 'file'" label="文件类型">{{ data.valueType?.fileType }}</a-descriptions-item>
<a-descriptions-item v-if="data.valueType.type === 'date'" label="格式">{{ data.valueType?.format }}</a-descriptions-item>
<a-descriptions-item
v-if="
['enum', 'object', 'boolean', 'array'].includes(data.valueType.type)"
>
<JsonView :value="dataTypeTable.dataSource"/>
</a-descriptions-item>
<a-descriptions-item label="读写类型">{{ readTypeText }}</a-descriptions-item>
</j-descriptions>
<template #footer>
<j-button type="primary" @click="ok">确认</j-button>
</template>
</j-modal>
</template>
<script setup lang="ts" name="TagsModal">
import {OtherConfigInfo} from "@/views/device/components/Metadata/Base/components";
import {omit} from "lodash-es";
import {watch} from "vue";
import JsonView from './JsonView.vue'
import {getUnit} from "@/api/device/instance";
const props = defineProps({
data: {
type: Object,
default: () => ({})
}
})
const emit = defineEmits(['cancel'])
const sourceMap = {
'device': '设备',
'manual': '手动',
'rule': '规则',
}
const readTypeText = computed(() => {
const type = {
"read": "读",
"write": "写",
"report": "上报",
}
return props.data?.expands?.type?.map?.((key: string) => type[key]).join('、')
})
const unitLabel = ref('')
const dataTypeTable = reactive<{ columns: any[], dataSource: any }>({
columns: [],
dataSource: []
})
const metrics = reactive<{ columns: any[], dataSource: any }>({
columns: [
{ title: '指标标识', dataIndex: 'id' },
{ title: '指标名称', dataIndex: 'name' },
{ title: '指标治', dataIndex: 'value' },
],
dataSource: []
})
const showSetting = computed(() => {
const setting = omit((props.data?.expands || {}), ['type', 'source'])
return Object.values(setting).length
})
const handleDataTable = (type: string) => {
switch (type) {
case 'enum':
dataTypeTable.columns = [
{ title: 'Value', dataIndex: 'value'},
{ title: 'Text', dataIndex: 'text'},
]
dataTypeTable.dataSource = props.data.valueType?.elements
break;
case 'object':
dataTypeTable.columns = [
{ title: '标识', dataIndex: 'id', width: 50},
{ title: '名称', dataIndex: 'name'},
{ title: '名称', dataIndex: 'name'},
]
dataTypeTable.dataSource = props.data.valueType?.properties
break;
case 'boolean':
dataTypeTable.dataSource = {
...omit(props.data.valueType, ['type'])
}
break;
case 'array':
dataTypeTable.dataSource = props.data.valueType.elementType
break;
}
}
watch(() => props.data.valueType.type, () => {
const type = props.data.valueType.type
handleDataTable(props.data.valueType.type)
if (['float', 'double', 'int', 'long'].includes(type)) {
getUnit().then((res) => {
if (res.success) {
res.result.map((item) => {
if (item.id === props.data.valueType?.unit) {
unitLabel.value = item.description
}
})
}
});
}
}, { immediate: true })
const cancel = () => {
emit('cancel')
}
const ok = () => {
cancel()
}
</script>
<style scoped>
</style>

View File

@ -1,3 +1,4 @@
export { default as PropertiesModal } from './PropertiesModal.vue'
export { default as FunctionModal } from './FunctionModal.vue'
export { default as EventModal } from './EventModal.vue'
export { default as TagsModal } from './TagsModal.vue'

View File

@ -6,6 +6,7 @@ import { EventLevel } from "@/views/device/data";
import {MetadataType} from "@/views/device/Product/typings";
import { getUnit } from '@/api/device/instance';
import {Ref} from "vue";
import {omit} from "lodash-es";
interface DataTableColumnProps extends ColumnProps {
type?: string,
components?: {
@ -39,7 +40,9 @@ export const handleTypeValue = (type:string, value: any = {}) => {
obj.elementType = value
break;
case 'object':
obj.properties = value
obj.properties = (value || []).map((item: any) => {
return omit(item, ['config', 'action', '_sortIndex'])
})
break;
case 'int':
case 'long':
@ -119,13 +122,19 @@ export const useColumns = (type?: MetadataType, target?: 'device' | 'product', n
const fieldIndex = Number(field[1])
const hasId = dataSource.some((item, index) => item.id === value && fieldIndex !== index)
if (hasId) {
return Promise.reject('该标识存在')
return Promise.reject('该标识存在')
}
return Promise.resolve()
}
return Promise.reject('请输入标识')
}
}]
},
},
{ max: 64, message: '最多可输入64个字符' },
{
pattern: /^[a-zA-Z0-9_\-]+$/,
message: 'ID只能由数字、字母、下划线、中划线组成',
},
]
},
doubleClick(record) {
const ids = (noEdit?.value?.id || []) as any[]
@ -139,10 +148,13 @@ export const useColumns = (type?: MetadataType, target?: 'device' | 'product', n
type: 'text',
form: {
required: true,
rules: [{
required: true,
message: '请输入名称'
}]
rules: [
{
required: true,
message: '请输入名称'
},
{ max: 64, message: '最多可输入64个字符' },
]
}
},
];
@ -262,9 +274,10 @@ export const useColumns = (type?: MetadataType, target?: 'device' | 'product', n
},
form: {
required: true,
rules: [
rules: target !== 'device' ? [
{
validator: async (_: Record<string, any>, value: any) => {
console.log('expands',value)
if (value.source) {
if(value.source !== 'rule') {
if(value.type?.length) {
@ -284,7 +297,7 @@ export const useColumns = (type?: MetadataType, target?: 'device' | 'product', n
}
}
},
]
]: []
},
width: 150
},
@ -307,7 +320,19 @@ export const useColumns = (type?: MetadataType, target?: 'device' | 'product', n
type: 'components',
components: {
name: DataType,
}
},
form: {
required: true,
rules: [{
validator(_: any, value: any) {
console.log('validator',value)
if (!value?.type) {
return Promise.reject('请选择数据类型')
}
return Promise.resolve()
}
}]
},
},
{
title: '读写类型',
@ -332,7 +357,6 @@ export const useColumns = (type?: MetadataType, target?: 'device' | 'product', n
const columns = ref<any[]>([])
watch(() => JSON.stringify(noEdit!.value), () => {
console.log(noEdit!.value)
switch(type) {
case 'properties':
columns.value = PropertyColumns
@ -356,22 +380,40 @@ export const useUnit = (type: Ref<string>) => {
const unitOptions = ref<Array<{ label: string, value: any }>>([])
watch(() => type.value, () => {
console.log('type.value',type.value)
if (['float', 'double', 'int', 'long'].includes(type.value) && !unitOptions.value.length) {
getUnit().then((res) => {
if (res.success) {
unitOptions.value = res.result.map((item: any) => ({
label: item.description,
value: item.id,
}));
}
});
}
})
}));
}
});
}
}, { immediate: true })
return { unitOptions }
}
export const TypeStringMap = {
int: 'int(整数型)',
long: 'long(长整数型)',
float: 'float(单精度浮点型)',
double: 'double(双精度浮点数)',
string: 'text(字符串)',
boolean: 'boolean(布尔型)',
date: 'date(时间型)',
enum: 'enum(枚举)',
array: 'array(数组)',
object: 'object(结构体)',
file: 'file(文件)',
password: 'password(密码)',
geoPoint: 'geoPoint(地理位置)',
}
// const MetadataMapping = new Map<string, DataTableColumnProps[]>();
// MetadataMapping.set('properties', PropertyColumns);
// MetadataMapping.set('events', EventColumns);

View File

@ -6,94 +6,23 @@
placement="topRight"
@confirm="valueChange"
>
<j-button>
<AIcon type="SettingOutlined" />
配置
</j-button>
<ModelButton />
</DataTableArray>
<DataTableObject
v-else-if="type === 'object'"
v-else-if="type === 'object' && showOther"
:value="myValue.properties"
placement="topRight"
:onAdd="objectAdd"
:columns="[
{
title: '参数标识',
dataIndex: 'id',
type: 'text',
width: 100,
form: {
required: true,
rules: [
{
callback(rule:any,value: any, _dataSource: any[]) {
if (value) {
const field = rule.field.split('.')
const fieldIndex = Number(field[1])
const hasId = _dataSource.some((item, index) => item.id === value && fieldIndex !== index)
if (hasId) {
return Promise.reject('该标识存在')
}
return Promise.resolve()
}
return Promise.reject('请输入标识')
}
}
]
}
},
{
title: '参数名称',
dataIndex: 'name',
type: 'text',
width: 100,
form: {
required: true,
rules: [{
required: true,
message: '请输入参数名称'
}]
}
},
{
title: '数据类型',
type: 'components',
dataIndex: 'valueType',
components: {
name: ValueObject,
props: {
filter: ['object']
}
},
width: 100
},
{
title: '其他配置',
type: 'components',
dataIndex: 'config',
components: {
name: DataTypeObjectChild
},
width: 100
},
{
title: '操作',
dataIndex: 'action',
width: 60
}
]"
:columns="columns"
@confirm="valueChange"
>
<template #valueType="{ data }">
{{ data.record.valueType?.type }}
{{ TypeStringMap[data.record.valueType?.type] }}
</template>
<template #config="{ data }">
<OtherConfigInfo :value="data.record.valueType"></OtherConfigInfo>
</template>
<j-button>
<AIcon type="SettingOutlined" />
配置
</j-button>
<ModelButton />
</DataTableObject>
<DataTableEnum
v-else-if="type === 'enum'"
@ -101,10 +30,7 @@
placement="topRight"
@confirm="valueChange"
>
<j-button>
<AIcon type="SettingOutlined" />
配置
</j-button>
<ModelButton />
</DataTableEnum>
<DataTableBoolean
v-else-if="type === 'boolean'"
@ -112,34 +38,26 @@
placement="topRight"
@confirm="valueChange"
>
<j-button>
<AIcon type="SettingOutlined" />
配置
</j-button>
<ModelButton />
</DataTableBoolean>
<DataTableDouble
v-else-if="['float', 'double'].includes(type)"
:options="unitOptions"
:showUnit="false"
v-model:value="myValue"
placement="topRight"
@confirm="valueChange"
>
<j-button>
<AIcon type="SettingOutlined" />
配置
</j-button>
<ModelButton />
</DataTableDouble>
<DataTableInteger
v-else-if="['int', 'long'].includes(type)"
v-else-if="['int', 'long'].includes(type) && showOther"
:options="unitOptions"
v-model:value="myValue.unit"
placement="topRight"
@confirm="valueChange"
>
<j-button>
<AIcon type="SettingOutlined" />
配置
</j-button>
<ModelButton />
</DataTableInteger>
<DataTableFile
v-else-if="type === 'file'"
@ -147,10 +65,7 @@
placement="topRight"
@confirm="valueChange"
>
<j-button>
<AIcon type="SettingOutlined" />
配置
</j-button>
<ModelButton />
</DataTableFile>
<DataTableDate
v-else-if="type === 'date'"
@ -158,20 +73,14 @@
placement="topRight"
@confirm="valueChange"
>
<j-button>
<AIcon type="SettingOutlined" />
配置
</j-button>
<ModelButton />
</DataTableDate>
<DataTableString
v-else-if="['string', 'password'].includes(type)"
v-model:value="myValue.maxLength"
placement="topRight"
>
<j-button>
<AIcon type="SettingOutlined" />
配置
</j-button>
<ModelButton />
</DataTableString>
<span v-else>
@ -203,11 +112,16 @@ const props = defineProps({
valueKey: {
type: String,
default: 'valueType'
},
showOther: {
type: Boolean,
default: true
}
})
const emit = defineEmits(['update:value'])
import {useUnit} from "@/views/device/components/Metadata/Base/columns";
import {handleTypeValue, TypeStringMap, useUnit} from "@/views/device/components/Metadata/Base/columns";
import ModelButton from '@/views/device/components/Metadata/Base/components/ModelButton.vue'
const objectAdd = () => {
return {
@ -221,20 +135,113 @@ const objectAdd = () => {
const options = ref([])
const type = ref(props.value?.[props.valueKey]?.type)
const type = ref(props.value?.type)
const { unitOptions } = useUnit(type)
const myValue = ref(props.value?.[props.valueKey])
const myValue = ref(props.value)
const valueChange = () => {
const columns = [
{
title: '参数标识',
dataIndex: 'id',
type: 'text',
width: 100,
form: {
required: true,
rules: [
{
callback(rule:any,value: any, _dataSource: any[]) {
if (value) {
const field = rule.field.split('.')
const fieldIndex = Number(field[1])
const hasId = _dataSource.some((item, index) => item.id === value && fieldIndex !== index)
if (hasId) {
return Promise.reject('该标识已存在')
}
return Promise.resolve()
}
return Promise.reject('请输入标识')
}
},
{ max: 64, message: '最多可输入64个字符' },
{
pattern: /^[a-zA-Z0-9_\-]+$/,
message: 'ID只能由数字、字母、下划线、中划线组成',
},
]
}
},
{
title: '参数名称',
dataIndex: 'name',
type: 'text',
width: 100,
form: {
required: true,
rules: [{
required: true,
message: '请输入参数名称'
},
{ max: 64, message: '最多可输入64个字符' }
]
}
},
{
title: '数据类型',
type: 'components',
dataIndex: 'valueType',
components: {
name: ValueObject,
},
form: {
required: true,
rules: [{
validator(_: any, value: any) {
console.log('validator',value)
if (!value?.type) {
return Promise.reject('请选择数据类型')
}
return Promise.resolve()
}
}]
},
width: 100
},
{
title: '其他配置',
type: 'components',
dataIndex: 'config',
components: {
name: DataTypeObjectChild
},
width: 100
},
{
title: '操作',
dataIndex: 'action',
width: 60
}
]
const valueChange = (data: any) => {
console.log('configModal - confirm',data, props.value, type.value)
const newObj = handleTypeValue(type.value, data)
console.log('configModal - newObj', newObj)
console.log('configModal - newObj2', {
type: type.value,
...newObj
})
emit('update:value', {
type: type.value,
...newObj
})
}
watch(() => JSON.stringify(props.value), () => {
console.log(props.value)
type.value = props.value?.[props.valueKey]?.type
myValue.value = props.value?.[props.valueKey]
type.value = props.value?.type
myValue.value = props.value
})
</script>

View File

@ -18,25 +18,25 @@
@confirm="(data) => {valueChange(data, 'object')}"
>
<template #valueType="{ data }">
{{ data.record.valueType?.type }}
{{ TypeStringMap[data.record.valueType?.type] }}
</template>
<template #config="{ data }">
<!-- <OtherConfigInfo :value="data.record.valueType"></OtherConfigInfo>-->
<ConfigModal v-model:value="data.record" :unitOptions="unitOptions" />
<ConfigModal v-model:value="data.record.valueType" :showOther="false" />
</template>
</DataTableObject>
<DataTableEnum v-else-if="type === 'enum'" v-model:value="_valueType" placement="topRight" @confirm="(data) => {valueChange(data, 'enum')}"/>
<DataTableBoolean v-else-if="type === 'boolean'" v-model:value="_valueType" placement="topRight" @confirm="(data) => {valueChange(data, 'boolean')}" />
<DataTableDouble
v-else-if="['float', 'double'].includes(type)"
:options="options"
:options="unitOptions"
v-model:value="_valueType"
placement="topRight"
@confirm="(data) => {valueChange(data, 'float')}"
/>
<DataTableInteger
v-else-if="['int', 'long'].includes(type)"
:options="options"
:options="unitOptions"
v-model:value="_valueType.unit"
placement="topRight"
@confirm="(data) => {valueChange(data, 'int')}"
@ -68,8 +68,9 @@ import {
DataTableObject,
} from 'jetlinks-ui-components';
import { cloneDeep } from 'lodash-es';
import {handleTypeValue, typeSelectChange, useUnit } from '../columns'
import {handleTypeValue, typeSelectChange, TypeStringMap, useUnit} from '../columns'
import ConfigModal from './ConfigModal.vue'
import { Form } from 'jetlinks-ui-components'
const props = defineProps({
value: {
@ -78,6 +79,8 @@ const props = defineProps({
},
});
const formItemContext = Form.useInjectFormItemContext();
const columns = [{
title: '参数标识',
dataIndex: 'id',
@ -86,10 +89,25 @@ const columns = [{
form: {
required: true,
rules: [{
callback() {
return Promise.resolve()
}
}]
callback(rule:any,value: any, dataSource: any[]) {
if (value) {
const field = rule.field.split('.')
const fieldIndex = Number(field[1])
const hasId = dataSource.some((item, index) => item.id === value && fieldIndex !== index)
if (hasId) {
return Promise.reject('该标识已存在')
}
return Promise.resolve()
}
return Promise.reject('请输入标识')
},
},
{ max: 64, message: '最多可输入64个字符' },
{
pattern: /^[a-zA-Z0-9_\-]+$/,
message: 'ID只能由数字、字母、下划线、中划线组成',
},
]
}
},
{
@ -102,7 +120,9 @@ const columns = [{
rules: [{
required: true,
message: '请输入参数名称'
}]
},
{ max: 64, message: '最多可输入64个字符' },
]
}
},
{
@ -111,9 +131,18 @@ const columns = [{
dataIndex: 'valueType',
components: {
name: ValueObject,
props: {
filter: ['object']
}
},
form: {
required: true,
rules: [{
validator(_: any, value: any) {
console.log('validator',value)
if (!value?.type) {
return Promise.reject('请选择数据类型')
}
return Promise.resolve()
}
}]
},
width: 100
},
@ -143,16 +172,16 @@ const typeChange = (e: string) => {
...props.value,
valueType: { ...obj, type: e }
});
formItemContext.onFieldChange()
};
const valueChange = (_data: any, _type: string) => {
console.log(_type, _data)
const newData = handleTypeValue(_type, _data)
console.log('dataType',{...newData, type: type.value})
emit('update:value', {
...props.value,
valueType: {...newData, type: type.value},
});
formItemContext.onFieldChange()
}
const { unitOptions } = useUnit(type)

View File

@ -1,19 +1,16 @@
<template>
<DataTableObject v-model:value="value" :columns="columns" @confirm="confirm">
<template #valueType="{ data }">
<span>{{ data.record.valueType?.type }}</span>
<span>{{ TypeStringMap[data.record.valueType?.type] }}</span>
</template>
<template #config="{ data }">
<ConfigModal v-model:value="data.record" />
<ConfigModal v-model:value="data.record.valueType" :showOther="false" />
</template>
<j-button>
<AIcon type="SettingOutlined" />
配置
</j-button>
<ModelButton />
</DataTableObject>
</template>
<script setup lang="ts" name="InputParams">
<script setup lang="ts" name="ConfigParams">
import type { PropType } from 'vue';
import {
DataTableObject,
@ -21,6 +18,9 @@ import {
import { ValueObject } from '../index'
import ConfigModal from '@/views/device/components/Metadata/Base/components/ConfigModal.vue'
import ModelButton from '@/views/device/components/Metadata/Base/components/ModelButton.vue'
import {omit} from "lodash-es";
import {TypeStringMap} from "../../columns";
const columns = [
{
@ -36,13 +36,19 @@ const columns = [
const fieldIndex = Number(field[1])
const hasId = _dataSource.some((item, index) => item.id === value && fieldIndex !== index)
if (hasId) {
return Promise.reject('该标识存在')
return Promise.reject('该标识存在')
}
return Promise.resolve()
}
return Promise.reject('请输入标识')
}
}]
},
{ max: 64, message: '最多可输入64个字符' },
{
pattern: /^[a-zA-Z0-9_\-]+$/,
message: 'ID只能由数字、字母、下划线、中划线组成',
},
]
}
},
{
@ -53,8 +59,10 @@ const columns = [
required: true,
rules: [{
required: true,
message: '请输入参数标识名称'
}]
message: '请输入参数名称'
},
{ max: 64, message: '最多可输入64个字符' },
]
}
},
{
@ -63,10 +71,19 @@ const columns = [
dataIndex: 'valueType',
components: {
name: ValueObject,
props: {
filter: ['object']
}
},
form: {
required: true,
rules: [{
validator(_: any, value: any) {
console.log('validator',value)
if (!value?.type) {
return Promise.reject('请选择数据类型')
}
return Promise.resolve()
}
}]
}
},
{
title: '其他配置',
@ -87,8 +104,8 @@ type Emits = {
const emit = defineEmits<Emits>();
const props = defineProps({
value: {
type: Object as PropType<Record<string, any>>,
default: () => {},
type: Object,
default: () => ({}),
},
placeholder: {
type: String,
@ -100,35 +117,26 @@ const props = defineProps({
},
});
const value = ref(props.value.valueType?.properties);
const type = computed(() => {
return props.value.valueType?.type
})
const change = (v: string) => {
emit('update:value', { ...props.value, async: value.value });
emit('change', v);
};
const value = ref(props.value.properties);
const confirm = (data: any) => {
console.log('ConfigParams',data)
const newObject = data.map((item) => {
const { config, action, _sortIndex, ...extra } = item
return extra
return omit(item, ['_sortIndex', 'config', 'action'])
})
console.log('ConfigParams',newObject)
emit('update:value', {
...props.value,
valueType: {
properties: newObject,
type: props.value.valueType.type,
}
properties: newObject,
type: 'object',
})
}
watch(
() => props.value,
(newV) => {
value.value = props.value.valueType?.properties;
value.value = props.value.properties;
},
{ immediate: true },
);

View File

@ -1,18 +1,15 @@
<template>
<DataTableObject :value="dataSource" :columns="columns" :onAdd="addItem" width="700px" @confirm="confirm">
<DataTableObject :value="value" :columns="columns" :onAdd="addItem" width="700px" @confirm="confirm">
<template #valueType="{ data }">
<span>{{ data.record.valueType?.type }}</span>
<span>{{ TypeStringMap[data.record.valueType?.type] }}</span>
</template>
<template #required="{ data }">
<span>{{ data.record.expands?.required ? "是": '否' }}</span>
</template>
<template #config="{ data }">
<ConfigModal v-model:value="data.record" />
<ConfigModal v-model:value="data.record.valueType" :showOther="false" />
</template>
<j-button>
<AIcon type="SettingOutlined" />
配置
</j-button>
<ModelButton />
</DataTableObject>
</template>
@ -23,7 +20,8 @@ import {
DataTableObject,
} from 'jetlinks-ui-components';
import { ConstraintSelect, ValueObject } from '../index'
import {TypeStringMap} from "../../columns";
import ModelButton from '@/views/device/components/Metadata/Base/components/ModelButton.vue'
type Emits = {
(e: 'update:value', data: Record<string, any>): void;
@ -33,8 +31,8 @@ type Emits = {
const emit = defineEmits<Emits>();
const props = defineProps({
value: {
type: Object as PropType<Record<string, any>>,
default: () => {},
type: Array,
default: () => [],
},
placeholder: {
type: String,
@ -68,7 +66,6 @@ const columns = ref([
form: {
required: true,
rules: [
{ required: true, message: '请输入标识' },
{
callback(rule:any,value: any, _dataSource: any[]) {
if (value) {
@ -76,17 +73,30 @@ const columns = ref([
const fieldIndex = Number(field[1])
const hasId = _dataSource.some((item, index) => item.id === value && fieldIndex !== index)
if (hasId) {
return Promise.reject('该标识存在')
return Promise.reject('该标识存在')
}
return Promise.resolve()
}
return Promise.reject('请输入标识')
}
},
{ max: 64, message: '最多可输入64个字符' },
{
pattern: /^[a-zA-Z0-9_\-]+$/,
message: 'ID只能由数字、字母、下划线、中划线组成',
},
]
}
},
{ title: '参数名称', dataIndex: 'name', type: 'text', form: { required: true, rules: [{ required: true, message: '请输入名称'}]} },
{
title: '参数名称',
dataIndex: 'name',
type: 'text',
form: {
required: true,
rules: [{ required: true, message: '请输入名称'}, { max: 64, message: '最多可输入64个字符' },]
}
},
{
title: '填写约束',
dataIndex: 'required',
@ -102,9 +112,18 @@ const columns = ref([
dataIndex: 'valueType',
components: {
name: ValueObject,
form: {
required: true
}
},
form: {
required: true,
rules: [{
validator(_: any, value: any) {
console.log('validator',value)
if (!value?.type) {
return Promise.reject('请选择数据类型')
}
return Promise.resolve()
}
}]
},
},
{
@ -118,28 +137,20 @@ const columns = ref([
},
])
const dataSource = ref(props.value);
// const dataSource = ref(props.value.inputs);
const change = (v: string) => {
emit('update:value', { ...props.value, async: dataSource.value });
emit('change', v);
};
watch(
() => JSON.stringify(props.value),
(newV) => {
console.log('inputParams-change')
dataSource.value = props.value.inputs;
},
{ immediate: true },
);
// watch(
// () => JSON.stringify(props.value),
// (newV) => {
// console.log('inputParams-change', props.value.inputs)
// dataSource.value = props.value.inputs;
// },
// { immediate: true },
// );
const confirm = (v: any) => {
console.log('inputParams',v)
emit('update:value', {
...props.value,
inputs: v
})
emit('update:value', v)
}
</script>

View File

@ -12,74 +12,15 @@
v-else-if="type === 'object'"
v-model:value="data.properties"
placement="topRight"
:columns="[
{
title: '参数标识',
dataIndex: 'id',
type: 'text',
form: {
required: true,
rules: [{
callback(rule:any,value: any, dataSource: any[]) {
if (value) {
const field = rule.field.split('.')
const fieldIndex = Number(field[1])
const hasId = dataSource.some((item, index) => item.id === value && fieldIndex !== index)
if (hasId) {
return Promise.reject('该标识存在')
}
return Promise.resolve()
}
return Promise.reject('请输入标识')
}
}]
}
},
{
title: '参数名称',
dataIndex: 'name',
type: 'text',
form: {
required: true,
rules: [{
required: true,
message: '请输入参数名称'
}]
}
},
{
title: '数据类型',
type: 'components',
dataIndex: 'valueType',
components: {
name: Type,
},
form: {
required: true,
rules: [{
required: true,
message: '请选择数据类型'
}]
}
},
{
title: '其他配置',
dataIndex: 'config',
},
{
title: '操作',
dataIndex: 'action',
width: 60
}
]"
:columns="columns"
@confirm="valueChange"
:onAdd="addItem"
>
<template #valueType="{ data }">
<span>{{ data.record.valueType?.type }}</span>
<span>{{ TypeStringMap[data.record.valueType?.type] }}</span>
</template>
<template #config="{ data }">
<ConfigModal v-model:value="data.record" />
<ConfigModal v-model:value="data.record.valueType" :showOther="false"/>
</template>
</DataTableObject>
<DataTableEnum v-else-if="type === 'enum'" v-model:value="data" @confirm="valueChange"/>
@ -123,7 +64,7 @@ import {
import ConfigModal from '@/views/device/components/Metadata/Base/components/ConfigModal.vue'
import { cloneDeep } from 'lodash-es';
import {typeSelectChange, useUnit} from "@/views/device/components/Metadata/Base/columns";
import {typeSelectChange, TypeStringMap, useUnit} from "@/views/device/components/Metadata/Base/columns";
import Type from './Type.vue'
const props = defineProps({
@ -138,7 +79,7 @@ const options = ref<{ label: string; value: string }[]>([]);
const emit = defineEmits(['update:value']);
const type = ref(props.value?.output?.type);
const data = ref(cloneDeep(props.value?.output));
const data = ref(props.value?.output);
const { unitOptions } = useUnit(type)
@ -150,6 +91,80 @@ const typeChange = (e: string) => {
});
};
const columns = [
{
title: '参数标识',
dataIndex: 'id',
type: 'text',
form: {
required: true,
rules: [{
callback(rule:any,value: any, dataSource: any[]) {
if (value) {
const field = rule.field.split('.')
const fieldIndex = Number(field[1])
const hasId = dataSource.some((item, index) => item.id === value && fieldIndex !== index)
if (hasId) {
return Promise.reject('该标识已存在')
}
return Promise.resolve()
}
return Promise.reject('请输入标识')
}
},
{ max: 64, message: '最多可输入64个字符' },
{
pattern: /^[a-zA-Z0-9_\-]+$/,
message: 'ID只能由数字、字母、下划线、中划线组成',
},
]
}
},
{
title: '参数名称',
dataIndex: 'name',
type: 'text',
form: {
required: true,
rules: [{
required: true,
message: '请输入参数名称'
},
{ max: 64, message: '最多可输入64个字符' },
]
}
},
{
title: '数据类型',
type: 'components',
dataIndex: 'valueType',
components: {
name: Type,
},
form: {
required: true,
rules: [{
validator(_: any, value: any) {
console.log('validator',value)
if (!value?.type) {
return Promise.reject('请选择数据类型')
}
return Promise.resolve()
}
}]
}
},
{
title: '其他配置',
dataIndex: 'config',
},
{
title: '操作',
dataIndex: 'action',
width: 60
}
]
watch(
() => props.value,
() => {

View File

@ -1,7 +1,6 @@
<template>
<DataTableTypeSelect
v-model:value="myValue"
:filter="['object']"
@change="change"
/>
</template>

View File

@ -0,0 +1,14 @@
<template>
<j-button type="link" stype="padding-left: 0;">
<AIcon type="SettingOutlined" />
配置
</j-button>
</template>
<script setup name="ModelButton">
</script>
<style scoped>
</style>

View File

@ -11,7 +11,7 @@
{{ data.record.range === 'true' ? '范围值' : '固定值'}}
</template>
<template #value="{data}">
{{ data.record.range === 'true' ? data.record.value?.toString() : data.record.value }}
{{ data.record.range === 'true' ? data.record.value?.join('-') : data.record.value }}
</template>
<template #action="{data}">
<j-button
@ -22,7 +22,7 @@
</j-button>
</template>
</j-data-table>
<j-button style="width: 100%;margin-top: 16px;" @click="addItem">
<j-button style="width: 100%;margin-top: 16px;" @click="addItem" >
<template #icon><AIcon type="PlusOutlined" /></template>
添加指标值
</j-button>

View File

@ -37,7 +37,7 @@
<AIcon type="ExclamationCircleOutlined" style="padding-left: 12px;padding-top: 4px;" />
</j-tooltip>
</template>
<Metrics ref="metricsRef" :value="myValue.expands?.metrics" :type="props.value?.valueType?.type"/>
<Metrics ref="metricsRef" :value="myValue.metrics" :type="props.type"/>
</j-collapse-panel>
</j-collapse>
@ -49,10 +49,7 @@
</div>
</template>
<j-button>
<AIcon type="SettingOutlined" />
配置
</j-button>
<ModelButton />
</j-popconfirm-modal>
</template>
@ -63,12 +60,17 @@ import {cloneDeep} from "lodash";
import {useProductStore} from "store/product";
import {useInstanceStore} from "store/instance";
import {getMetadataConfig, getMetadataDeviceConfig} from "@/api/device/product";
import ModelButton from '@/views/device/components/Metadata/Base/components/ModelButton.vue'
import {omit} from "lodash-es";
const props = defineProps({
value: {
type: Object,
default: () => ({})
},
type: {
type: String,
default: undefined
}
})
@ -90,7 +92,7 @@ const config = ref<any>([])
const configValue = ref(props.value?.expands)
const showMetrics = computed(() => {
return ['int', 'long', 'float', 'double', 'string', 'boolean', 'date'].includes(props.value?.valueType?.type as any)
return ['int', 'long', 'float', 'double', 'string', 'boolean', 'date'].includes(props.type as any)
})
const columns = ref([
@ -114,15 +116,14 @@ const columns = ref([
const getConfig = async () => {
const record = props.value
const id = type === 'product' ? productStore.current?.id : deviceStore.current.id
console.log(record.id, id, record.valueType)
if(!record.id || !id || !record.valueType.type) return
if(!record.id || !id || !record.type) return
const params: any = {
deviceId: id,
metadata: {
id: record.id,
type: 'property',
dataType: record.valueType.type,
dataType: record.type,
},
}
@ -162,17 +163,12 @@ const confirm = () => {
if (metrics) {
expands.metrics = metrics
}
console.log(expands)
emit('update:value', {
...props.value,
expands: {
...(props.value.expands || {}),
...expands
}
...expands
})
resolve(true)
} catch (err) {
console.log(err)
reject(false)
}
})
@ -180,18 +176,16 @@ const confirm = () => {
const visibleChange = (e: boolean) => {
if (e) {
configValue.value = omit(props.value?.expands, ['source', 'type', 'metrics', 'required'])
configValue.value = omit(props.value, ['source', 'type', 'metrics', 'required'])
getConfig()
}
}
const cancel = () => {
console.log(props.value)
myValue.value = cloneDeep(props.value)
}
watch(() => props.value, () => {
console.log(props.value)
myValue.value = cloneDeep(props.value)
}, {immediate: true, deep: true})

View File

@ -8,31 +8,32 @@
:disabled="disabled"
>
</j-select>
<j-popconfirm-modal
v-if="myValue != 'manual'"
@confirm="confirm"
:bodyStyle="{width: '450px', height: myValue === 'rule' ? '300px' : '80px'}"
>
<template #content>
<j-scrollbar v-if="myValue">
<VirtualRule
:value="value"
:source="myValue"
:dataSource="dataSource"
ref="virtualRuleRef"
/>
</j-scrollbar>
</template>
<j-button :disabled="!myValue" type="link" style="padding: 4px 8px">
<AIcon type="EditOutlined" />
</j-button>
</j-popconfirm-modal>
<j-popconfirm-modal
v-if="myValue != 'manual'"
@confirm="confirm"
:bodyStyle="{width: '450px', height: myValue === 'rule' ? '300px' : '80px'}"
>
<template #content>
<j-scrollbar v-if="myValue">
<VirtualRule
:value="value"
:source="myValue"
:dataSource="dataSource"
ref="virtualRuleRef"
/>
</j-scrollbar>
</template>
<j-button :disabled="!myValue" type="link" style="padding: 4px 8px">
<AIcon type="EditOutlined" />
</j-button>
</j-popconfirm-modal>
</div>
</template>
<script setup lang="ts" name="MetadataSource">
import { isNoCommunity } from '@/utils/utils';
import VirtualRule from './VirtualRule/index.vue';
import { Form } from 'jetlinks-ui-components'
const PropertySource: { label: string; value: string }[] = isNoCommunity
? [
@ -82,6 +83,7 @@ const props = defineProps({
});
const emit = defineEmits<Emit>();
const formItemContext = Form.useInjectFormItemContext();
const myValue = ref<SourceType>('');
const type = ref<string>('');
@ -93,20 +95,27 @@ const disabled = computed(() => {
return props.noEdit?.length ? props.noEdit.includes(props.value._sortIndex) :false
})
const updateValue = (data: any) => {
emit('update:value', {
...props.value,
expands: {
...(props.value?.expands || {}),
...data
}
})
formItemContext.onFieldChange()
}
const onChange = (keys: SourceType) => {
myValue.value = keys;
emit('update:value', {
...props.value,
expands: {
...props.value?.expands,
source: keys,
type:
keys === 'manual'
? ['write']
: keys === 'rule'
? ['report']
: [],
},
updateValue({
source: keys,
type:
keys === 'manual'
? ['write']
: keys === 'rule'
? ['report']
: [],
});
};
@ -116,15 +125,11 @@ const confirm = async () => {
reject();
});
if (data) {
const obj = {
...props.value,
expands: {
...props.value?.expands,
...data,
},
};
console.log(obj)
emit('update:value', obj);
console.log(data)
updateValue({
source: myValue.value,
...data
});
resolve(true);
} else {
reject()

View File

@ -17,12 +17,47 @@ const useMetadata = (type: 'device' | 'product', key?: MetadataType, ): {
const _metadataStr = type === 'product' ? productStore.current?.metadata : instanceStore.current.metadata
const _metadata = JSON.parse(_metadataStr || '{}')
const newMetadata = (key ? _metadata?.[key] || [] : []) as MetadataItem[]
console.log(key, _metadata, newMetadata)
const indexs = newMetadata.map((item, index) => index)
noEdit.value.id = indexs
const indexKeys = newMetadata.map((item, index) => index)
noEdit.value.id = indexKeys
if (key === 'properties') {
noEdit.value.source = indexs
noEdit.value.source = indexKeys
}
if (type === 'device' && instanceStore.current.productMetadata) {
const productMetadata: any = JSON.parse(instanceStore.current.productMetadata)
const metaArray = key ? productMetadata[key] : []
const productIndexKeys = metaArray?.map((item:any, index: number) => index) || []
noEdit.value.id = productIndexKeys
noEdit.value.name = productIndexKeys
if (key === 'properties') {
noEdit.value.valueType = productIndexKeys
noEdit.value.expands = productIndexKeys
}
if (key === 'functions') {
noEdit.value.async = productIndexKeys
noEdit.value.inputs = productIndexKeys
noEdit.value.output = productIndexKeys
noEdit.value.description = productIndexKeys
}
if (key === 'events') {
noEdit.value.expands = productIndexKeys
noEdit.value.outInput = productIndexKeys
noEdit.value.properties = productIndexKeys
noEdit.value.description = productIndexKeys
}
if (key === 'tags') {
noEdit.value.valueType = productIndexKeys
noEdit.value.readType = productIndexKeys
noEdit.value.description = productIndexKeys
}
}
return newMetadata
})

View File

@ -3823,10 +3823,22 @@ jetlinks-store@^0.0.3:
resolved "https://registry.npmjs.org/jetlinks-store/-/jetlinks-store-0.0.3.tgz"
integrity sha512-AZf/soh1hmmwjBZ00fr1emuMEydeReaI6IBTGByQYhTmK1Zd5pQAxC7WLek2snRAn/HHDgJfVz2hjditKThl6Q==
jetlinks-ui-components@^1.0.23, jetlinks-ui-components@^1.0.24:
jetlinks-ui-components@^1.0.23:
version "1.0.23"
resolved "http://registry.jetlinks.cn/jetlinks-ui-components/-/jetlinks-ui-components-1.0.23.tgz#6bef8fe635867a226afbfee3af6e870e46b0bf54"
integrity sha512-TtJJgtvW2aRvfD1BMTOulefPq3BUyfE02UARRF/XMo9GaPzPq7eqDonH4yrvadEd71cMPj2CYvt/A6FdWJu9yA==
dependencies:
"@vueuse/core" "^9.12.0"
"@vueuse/router" "^9.13.0"
ant-design-vue "^3.2.15"
colorpicker-v3 "^2.10.2"
lodash-es "^4.17.21"
monaco-editor "^0.35.0"
jetlinks-ui-components@^1.0.24:
version "1.0.24"
resolved "http://registry.jetlinks.cn/jetlinks-ui-components/-/jetlinks-ui-components-1.0.24.tgz#7d651f3d333ad52154f5dbbbcba7f6ed8e85e442"
integrity sha512-MtIwdFA2kq3s1rGLExYjjjuit05pjoIURDelUIE4swN3q9qh8QgHcjAOtwEor+UNp333LT2FnSQbMkfXctrqUQ==
resolved "http://registry.jetlinks.cn/jetlinks-ui-components/-/jetlinks-ui-components-1.0.24.tgz#68660b63aea9b4befeaa4c5e3ff121668bb984bb"
integrity sha512-09s73oEPKf+TC3KVL4suXrI4FjylJqyB2qXbFQtBOqyK/mSfMN/TJ7mcEoZdycBqAvmv35zTDKXIQIcvAAaitQ==
dependencies:
"@vueuse/core" "^9.12.0"
"@vueuse/router" "^9.13.0"