feat: 修改设备接入网关Modbus、opcua为数采设备接入

This commit is contained in:
XieYongHong 2023-07-25 14:18:38 +08:00
parent b52119fc6e
commit 80aa27a14e
17 changed files with 635 additions and 95 deletions

View File

@ -25,7 +25,7 @@
"event-source-polyfill": "^1.0.31",
"global": "^4.4.0",
"jetlinks-store": "^0.0.3",
"jetlinks-ui-components": "^1.0.26",
"jetlinks-ui-components": "^1.0.27",
"js-cookie": "^3.0.1",
"jsencrypt": "^3.3.2",
"less": "^4.1.3",

View File

@ -55,4 +55,5 @@ export const USER_CENTER_MENU_BUTTON_CODE = 'user-center-passwd-update'
export const protocolList = [
{ label: 'OPC-UA', value: 'OPC_UA', alias: 'opc-ua' },
{ label: 'Modbus/TCP', value: 'MODBUS_TCP', alias: 'modbus-tcp' },
{ label: 'GATEWAY', value: 'GATEWAY', alias: 'collector-gateway' },
]

View File

@ -0,0 +1,190 @@
<template>
<j-modal
:maskClosable="false"
:width='820'
title="选择网关设备"
visible
@cancel="cancel"
@ok="confirm"
>
<div>
<j-advanced-search
:columns="columns"
class="scene-search"
target="scene-triggrt-device-device"
type='simple'
@search="handleSearch"
/>
<j-divider style='margin: 0' />
<j-pro-table
ref='actionRef'
:bodyStyle='{
paddingRight: 0,
paddingLeft: 0
}'
:columns='columns'
:defaultParams="{
sorts: [{ name: 'createTime', order: 'desc' }],
terms: [{value: 'gateway', termType: 'eq', column: 'deviceType'}]
}"
:gridColumn='2'
:params='params'
:request='query'
:scroll="{y: 350}"
model='CARD'
>
<template #card="slotProps">
<CardBox
:active="selectKey.id === slotProps.id"
:status="slotProps.state?.value"
:statusNames="{
online: 'processing',
offline: 'error',
notActive: 'warning',
}"
:statusText="slotProps.state?.text"
:value='slotProps'
@click="handleClick"
>
<template #img>
<slot name="img">
<img :src="slotProps.photoUrl || getImage('/device/instance/device-card.png')" height='80' width='80' />
</slot>
</template>
<template #content>
<Ellipsis style='width: calc(100% - 100px)'>
<span style="font-size: 16px;font-weight: 600" >
{{ slotProps.name }}
</span>
</Ellipsis>
<j-row>
<j-col :span="12">
<div class="card-item-content-text">
设备类型
</div>
<div>{{ slotProps.deviceType?.text }}</div>
</j-col>
<j-col :span="12">
<div class="card-item-content-text">
产品名称
</div>
<div>{{ slotProps.productName }}</div>
</j-col>
</j-row>
</template>
</CardBox>
</template>
</j-pro-table>
</div>
</j-modal>
</template>
<script name="GateWayDevice" setup>
import { getImage } from '@/utils/comm'
import {query} from "@/api/device/instance";
const props = defineProps({
value: {
type: String,
default: undefined
},
name: {
type: String,
default: undefined
}
})
const emit = defineEmits(['cancel', 'confirm'])
const selectKey = reactive({
id: props.value,
name: props.name
})
const params = ref()
const columns = [
{
title: 'ID',
dataIndex: 'id',
width: 300,
ellipsis: true,
fixed: 'left',
search: {
type: 'string'
}
},
{
title: '设备名称',
dataIndex: 'name',
width: 200,
ellipsis: true,
search: {
type: 'string',
first: true
}
},
{
title: '创建时间',
dataIndex: 'createTime',
width: 200,
search: {
type: 'date'
}
},
{
title: '状态',
dataIndex: 'state',
width: 90,
search: {
type: 'select',
options: [
{ label: '禁用', value: 'notActive' },
{ label: '离线', value: 'offline' },
{ label: '在线', value: 'online' },
]
}
},
]
// const deviceQuery = (p) => {
// const sorts = [];
//
// if (props.rowKeys) {
// props.rowKeys.forEach(rowKey => {
// sorts.push({
// name: 'id',
// value: rowKey,
// });
// })
// }
// sorts.push({ name: 'createTime', order: 'desc' });
// const terms = [
// ...p.terms,
// { terms: [{ column: "productId", value: props.productId }]}
// ]
// return query({ ...p, terms, sorts })
// }
const handleClick = (detail) => {
console.log(detail)
selectKey.id = detail.id
selectKey.name = detail.name
}
const handleSearch = (p) => {
params.value = p
}
const cancel = () => {
emit('cancel')
}
const confirm = () => {
emit('confirm', selectKey)
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,71 @@
<template>
<j-button
v-if="!value"
style="width: 100%"
@click="showModal"
>
选择网关设备
</j-button>
<div v-else class="gateway-form-item">
<span>
<j-ellipsis>
{{ name }}
</j-ellipsis>
</span>
<j-button type="link" @click="showModal">
重新选择
</j-button>
</div>
<DeviceModal
v-if="visible"
:name="name"
:value="value"
@cancel="cancel"
@confirm="confirm"
/>
</template>
<script name="GateWayFormItem" setup>
import DeviceModal from './GateWayDeviceModal.vue'
const props = defineProps({
value: {
type: String,
default: undefined
},
name: {
type: String,
default: undefined
}
})
const emit = defineEmits(['update:value', 'update:name'])
const visible = ref(false)
const showModal = () =>{
visible.value = true
}
const cancel = () => {
visible.value = false
}
const confirm = (select) => {
console.log(select)
emit('update:value', select.id)
emit('update:name', select.name)
cancel()
}
</script>
<style lang="less" scoped>
.gateway-form-item {
display: flex;
>span {
line-height: 32px;
max-width: calc(100% - 88px);
}
}
</style>

View File

@ -92,6 +92,17 @@
:filter-option="filterOption"
/>
</j-form-item>
<j-form-item
v-if="formData.provider === 'GATEWAY'"
:name="['configuration','deviceId']"
:rules="[{ required: true, message: '请选择网关设备'}]"
label="选择网关设备"
>
<GateWayFormItem
v-model:name="formData.configuration.deviceName"
v-model:value="formData.configuration.deviceId"
/>
</j-form-item>
<j-form-item
v-if="formData.provider === 'OPC_UA'"
label="安全模式"
@ -198,6 +209,7 @@ import type { FormInstance } from 'ant-design-vue';
import type { FormDataType } from '../type.d';
import { cloneDeep, isArray } from 'lodash-es';
import { protocolList } from '@/utils/consts';
import GateWayFormItem from "@/views/DataCollect/Channel/Save/GateWayFormItem.vue";
const props = defineProps({
data: {
@ -222,7 +234,13 @@ const Options = ref({
const formData = ref<FormDataType>(cloneDeep(FormState));
const handleOk = async () => {
const params = await formRef.value?.validate();
const params: any = await formRef.value?.validate();
if (params?.provider === 'GATEWAY') {
params.configuration.deviceName = formData.value.configuration.deviceName
}
loading.value = true;
const response = !id
? await save(params).catch(() => {})
@ -284,7 +302,7 @@ const getProvidersList = async () => {
if (resp.status === 200) {
const arr = resp.result
.filter(
(item: any) => item.id === 'modbus-tcp' || item.id === 'opc-ua',
(item: any) => ['collector-gateway', 'modbus-tcp', 'opc-ua'].includes(item.id),
)
.map((it: any) => it.id);
const providers: any = protocolList.filter((item: any) =>
@ -302,7 +320,9 @@ getCertificateList();
watch(
() => props.data,
(value) => {
if (value.id) formData.value = value as FormDataType;
if (value.id) {
formData.value = value as FormDataType;
}
},
{ immediate: true, deep: true },
);

View File

@ -15,6 +15,8 @@ export const FormState: FormDataType = {
authType: 'anonymous',
username: '',
password: '',
deviceId: undefined,
deviceName: undefined,
},
description: '',
};

View File

@ -1,6 +1,6 @@
export interface ConfigurationType {
port: string | undefined;
host: string | undefined;;
host: string | undefined;
username: string;
password: string;
endpoint: string,
@ -8,7 +8,8 @@ export interface ConfigurationType {
securityMode: string | undefined,
certId: string | undefined,
authType: string | undefined,
deviceId: string | undefined,
deviceName: string | undefined,
}
export interface FormDataType {

View File

@ -20,7 +20,7 @@
<template #headerTitle>
<j-space>
<PermissionButton
v-if="data?.provider == 'MODBUS_TCP'"
v-if="['MODBUS_TCP', 'GATEWAY'].includes(data?.provider)"
type="primary"
@click="handlAdd"
hasPermission="DataCollect/Collector:add"

View File

@ -27,6 +27,7 @@
show-search
:filter-option="filterOption"
:disabled="!!id"
@select="channelSelect"
/>
</j-form-item>
<j-form-item
@ -39,12 +40,32 @@
v-model:value="formData.name"
/>
</j-form-item>
<j-form-item
label="从机地址"
:name="['configuration', 'unitId']"
v-if="visibleUnitId"
:rules="LeftTreeRules.unitId"
<template v-if="provider === 'GATEWAY'">
<j-form-item
label="通讯协议"
:name="['configuration', 'collectorProvider']"
:rules="[{ required: true, message: '请选择通讯协议' }]"
>
<j-select
style="width: 100%"
v-model:value="formData.configuration.collectorProvider"
:options="providerListItems"
placeholder="请选择通讯协议"
allowClear
show-search
:filter-option="filterOption"
:disabled="!!id"
/>
</j-form-item>
</template>
<template v-else>
<j-form-item
v-if="visibleUnitId"
:name="['configuration', 'unitId']"
:rules="LeftTreeRules.unitId"
label="从机地址"
>
<j-input-number
style="width: 100%"
placeholder="请输入从机地址"
@ -52,12 +73,12 @@
:min="0"
:max="255"
/>
</j-form-item>
<j-form-item
:name="['configuration', 'inheritBreakerSpec', 'type']"
:rules="LeftTreeRules.type"
label="点位熔断处理"
>
</j-form-item>
<j-form-item
:name="['configuration', 'inheritBreakerSpec', 'type']"
:rules="LeftTreeRules.type"
label="点位熔断处理"
>
<j-card-select
:showImage="false"
v-model:value="formData.configuration.inheritBreakerSpec.type"
@ -68,16 +89,16 @@
]"
@change="changeCardSelectType"
/>
</j-form-item>
<p style="color: #616161">
</j-form-item>
<p style="color: #616161">
{{ getTypeTooltip(formData.configuration.inheritBreakerSpec.type) }}
</p>
<j-form-item
label="双字高低位切换"
:name="['configuration', 'endian']"
v-if="visibleEndian"
:rules="LeftTreeRules.endian"
>
</p>
<j-form-item
v-if="visibleEndian"
:name="['configuration', 'endian']"
:rules="LeftTreeRules.endian"
label="双字高低位切换"
>
<j-card-select
:showImage="false"
v-model:value="formData.configuration.endian"
@ -88,13 +109,13 @@
@change="changeCardSelectEndian"
:column="2"
/>
</j-form-item>
<j-form-item
label="单字高低位切换"
:name="['configuration', 'endianIn']"
v-if="visibleEndian"
:rules="LeftTreeRules.endianIn"
>
</j-form-item>
<j-form-item
v-if="visibleEndian"
:name="['configuration', 'endianIn']"
:rules="LeftTreeRules.endianIn"
label="单字高低位切换"
>
<j-card-select
:showImage="false"
v-model:value="formData.configuration.endianIn"
@ -105,18 +126,18 @@
@change="changeCardSelectEndianIn"
:column="2"
/>
</j-form-item>
<div style="color: #616161" v-if="visibleEndian">
</j-form-item>
<div v-if="visibleEndian" style="color: #616161">
<p>当前内存布局: {{ endianData }}</p>
<p>
只有4字节数据类型(int32ieee754 float)
具有4种内存布局其它只有ABCDDCBA两种内存布局(以双字配置为准)
只有4字节数据类型(int32ieee754 float)
具有4种内存布局其它只有ABCDDCBA两种内存布局(以双字配置为准)
</p>
</div>
<j-form-item
label="请求超时时间配置"
:name="['configuration', 'requsetTimeout']"
>
</div>
<j-form-item
:name="['configuration', 'requsetTimeout']"
label="请求超时时间配置"
>
<j-input-number
style="width: 100%"
placeholder="请输入请求超时时间配置"
@ -125,8 +146,8 @@
:max="2147483648"
:min="1"
/>
</j-form-item>
</j-form-item>
</template>
<j-form-item label="说明" name="description">
<j-textarea
placeholder="请输入说明"
@ -154,11 +175,13 @@
</template>
</j-modal>
</template>
<script lang="ts" setup>
<script lang="ts" name="CollectorTreeSave" setup>
import { save, update } from '@/api/data-collect/collector';
import { LeftTreeRules } from '../../data';
import type { FormInstance } from 'ant-design-vue';
import {cloneDeep} from "lodash-es";
import {getProviders} from "@/api/data-collect/channel";
import {protocolList} from "@/utils/consts";
const loading = ref(false);
const visibleEndian = ref(false);
@ -179,17 +202,40 @@ const emit = defineEmits(['change']);
const id = props.data.id;
const formRef = ref<FormInstance>();
const provider = ref()
const providerListItems = ref()
const geyProviderList = async () => {
const resp: any = await getProviders();
if (resp.success) {
const arr = resp.result.filter(
(item: any) => ['collector-gateway', 'modbus-tcp', 'opc-ua'].includes(item.id),
).map((it: any) => it.id);
console.log(arr, protocolList)
providerListItems.value = protocolList.filter((item: any) =>
arr.includes(item.alias),
);
} else {
providerListItems.value = []
}
}
const _channelListAll = computed(() => {
return props.channelListAll || [];
})
const channelList = computed(() => {
return _channelListAll.value.map((item: any) => ({
provider: item.provider,
value: item.id,
label: item.name,
}));
})
const channelSelect = (key: string, detail: any) => {
console.log(detail)
provider.value = detail.provider
}
const endianData = computed(() => {
const { endian, endianIn } = formData.value.configuration;
@ -214,6 +260,7 @@ const formData = ref({
type: 'LowerFrequency',
endian: 'BIG',
endianIn: 'BIG',
collectorProvider: undefined,
requsetTimeout: 2000,
inheritBreakerSpec: {
type: 'LowerFrequency',
@ -229,13 +276,23 @@ const formData = ref({
const handleOk = async () => {
const data = await formRef.value?.validate();
const { provider, name } = _channelListAll.value.find(
const { name } = _channelListAll.value.find(
(item: any) => item.id === formData.value.channelId,
);
if (['GATEWAY'].includes(data?.provider)) {
data.configuration.inheritBreakerSpec.type = 'Ignore'
}
const params = {
...data,
provider,
provider: provider.value,
channelName: name,
circuitBreaker: {
type: 'Ignore'
}
};
loading.value = true;
@ -294,16 +351,28 @@ watch(
copyValue.configuration = {
...copyValue.configuration,
inheritBreakerSpec: {
type: value.circuitBreaker.type
type: value.circuitBreaker?.type
}
}
copyValue.circuitBreaker.type = 'Ignore'
}
formData.value = copyValue
const item = props.channelListAll.find(
(item: any) => item.id === formData.value.channelId,
);
provider.value = item?.provider
};
},
{ immediate: true, deep: true },
);
watchEffect(() => {
if (provider.value === 'GATEWAY') {
geyProviderList()
}
})
</script>
<style lang="less" scoped>

View File

@ -0,0 +1,7 @@
<template>
<EditTable provider="collector-gateway" />
</template>
<script lang="ts" setup>
import EditTable from '../components/EditTable/index.vue'
</script>

View File

@ -1,5 +1,5 @@
<template>
<j-spin :spinning="loading" v-if="metadata.properties.length">
<j-spin v-if="metadata.properties?.length" :spinning="loading">
<j-card :bordered="false" borderStyle="padding: 0">
<template #extra>
<j-space>
@ -188,16 +188,16 @@ const visible = ref<boolean>(false);
const getChannel = async () => {
const resp: any = await queryChannelNoPaging({
paging: false,
terms: [
{
terms: [
{
column: 'provider',
value: props.provider,
},
],
},
],
// terms: [
// {
// terms: [
// {
// column: 'provider',
// value: props.provider,
// },
// ],
// },
// ],
});
if (resp.status === 200) {
channelList.value = resp.result?.map((item: any) => ({
@ -211,12 +211,12 @@ const getChannel = async () => {
const handleSearch = async () => {
loading.value = true;
getChannel();
const _metadata = metadata.properties.map((item: any) => ({
const _metadata = metadata.properties?.map?.((item: any) => ({
metadataId: item.id,
metadataName: `${item.name}(${item.id})`,
metadataType: 'property',
name: item.name,
}));
})) || [];
if (_metadata && _metadata.length) {
const resp: any = await queryMapping(
'device',

View File

@ -122,6 +122,7 @@ import Modbus from './Modbus/index.vue';
import OPCUA from './OPCUA/index.vue';
import EdgeMap from './EdgeMap/index.vue';
import Parsing from './Parsing/index.vue';
import GateWay from './GateWay/index.vue'
import Log from './Log/index.vue';
import { _deploy, _disconnect } from '@/api/device/instance';
import { getImage, onlyMessage } from '@/utils/comm';
@ -181,7 +182,8 @@ const tabs = {
EdgeMap,
Parsing,
Log,
MetadataMap
MetadataMap,
GateWay
};
const getStatus = (id: string) => {
@ -225,7 +227,7 @@ const getDetail = () => {
) {
list.value.push({
key: 'Modbus',
tab: 'Modbus TCP',
tab: '数采映射',
});
}
if (
@ -234,9 +236,18 @@ const getDetail = () => {
) {
list.value.push({
key: 'OPCUA',
tab: 'OPC UA',
tab: '数采映射',
});
}
if (
instanceStore.current?.protocol === 'collector-gateway' &&
!keys.includes('GateWay')
) {
list.value.push({
key: 'GateWay',
tab: '数采映射',
});
}
if (
instanceStore.current?.deviceType?.value === 'gateway' &&
!keys.includes('ChildDevice')

View File

@ -14,40 +14,47 @@
<a @click="goBack">返回</a>
</div>
<template v-if="showType === 'network'">
<Network
v-if="provider.id !== 'plugin_gateway'"
:bindProduct='bindProduct'
:provider="provider"
:data="data"
/>
<Plugin
v-else
:bindProduct='bindProduct'
:provider="provider"
:data="data"
v-if="provider.id === 'plugin_gateway'"
:bindProduct='bindProduct'
:data="data"
:provider="provider"
/>
<GateWay
v-else-if="provider.id === 'collector-gateway'"
:bindProduct='bindProduct'
:data="data"
:provider="provider"
/>
<Network
v-else
:bindProduct='bindProduct'
:data="data"
:provider="provider"
/>
</template>
<Media
v-if="showType === 'media'"
v-else-if="showType === 'media'"
:bindProduct='bindProduct'
:provider="provider"
:data="data"
/>
<Channel
v-if="showType === 'channel'"
v-else-if="showType === 'channel'"
:bindProduct='bindProduct'
:provider="provider"
:data="data"
/>
<Edge
v-if="showType === 'edge'"
v-else-if="showType === 'edge'"
:bindProduct='bindProduct'
:provider="provider"
:data="data"
/>
<Cloud
v-if="showType === 'cloud'"
v-else-if="showType === 'cloud'"
:bindProduct='bindProduct'
:provider="provider"
:data="data"
@ -65,6 +72,7 @@ import Provider from '../components/Provider/index.vue';
import Media from '../components/Media/index.vue';
import Channel from '../components/Channel/index.vue';
import Edge from '../components/Edge/index.vue';
import GateWay from '../components/Edge/geteway.vue';
import Cloud from '../components/Cloud/index.vue';
import Plugin from '../components/Plugin/index.vue'
import { getProviders, detail } from '@/api/link/accessConfig';

View File

@ -0,0 +1,145 @@
<template>
<div class="card-last">
<j-row :gutter="[24, 24]">
<j-col :span="12">
<title-component data="基本信息" />
<div>
<j-form
:model="formState"
autocomplete="off"
layout="vertical"
name="basic"
@finish="onFinish"
>
<j-form-item
:rules="[
{
required: true,
message: '请输入名称',
trigger: 'blur',
},
{
max: 64,
message: '最多可输入64个字符',
trigger: 'blur',
},
]"
label="名称"
name="name"
>
<j-input
v-model:value="formState.name"
placeholder="请输入名称"
/>
</j-form-item>
<j-form-item label="说明" name="description">
<j-textarea
v-model:value="formState.description"
:maxlength="200"
:rows="4"
placeholder="请输入说明"
show-count
/>
</j-form-item>
<j-form-item>
<PermissionButton
v-if="view === 'false'"
:hasPermission="`link/AccessConfig:${
id === ':id' ? 'add' : 'update'
}`"
html-type="submit"
type="primary"
>
保存
</PermissionButton>
</j-form-item>
</j-form>
</div>
</j-col>
<j-col :span="12">
<div class="doc" style="height: 600px">
<TitleComponent data="配置概览" />
<p>接入方式{{ provider.name }}</p>
<p>
{{ provider.description }}
</p>
<p>设备接入指引</p>
<TitleComponent data="设备接入指引" />
<p>1数据采集菜单中配置数采通道点位</p>
<p>2创建数采设备接入网关</p>
<p>3创建产品并选中接入方式为数采设备接入</p>
<p>4添加设备单独为每一个设备进行数据点绑定</p>
</div>
</j-col>
</j-row>
</div>
</template>
<script lang="ts" name="GateWay" setup>
import { onlyMessage } from '@/utils/comm';
import { update, save } from '@/api/link/accessConfig';
import { ProtocolMapping } from '../../data';
interface FormState {
name: string;
description: string;
}
const route = useRoute();
const view = route.query.view as string;
const id = route.params.id as string;
const props = defineProps({
provider: {
type: Object,
default: () => {},
},
data: {
type: Object,
default: () => {},
},
});
const type = ref(props.provider.type || props.data.type);
const formState = ref<FormState>({
name: '',
description: '',
});
const onFinish = async (values: any) => {
const providerId = props.provider.id;
const params = {
...values,
provider: providerId,
protocol: providerId,
transport: ProtocolMapping.get(providerId),
channel: props.provider.channel,
};
const resp =
id === ':id' ? await save(params) : await update({ ...params, id });
if (resp.status === 200) {
onlyMessage('操作成功', 'success');
history.back();
if ((window as any).onTabSaveSuccess) {
(window as any).onTabSaveSuccess(resp);
setTimeout(() => window.close(), 300);
}
}
};
onMounted(() => {
if (id !== ':id') {
formState.value = {
name: props.data.name,
description: props.data?.description || '',
};
}
});
</script>
<style lang="less" scoped>
.card-last {
padding-right: 5px;
overflow-y: auto;
overflow-x: hidden;
}
</style>

View File

@ -151,17 +151,11 @@
/^([0-9]|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.([0-9]|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.([0-9]|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.([0-9]|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])$/,
message: '请输入正确的IP地址',
},
{
max: 65535,
message: '请输入1~65535之间的正整数'
},
{
min: 1,
message: '请输入1~65535之间的正整数'
},
]"
:validateFirst="true"
>
<j-input-number
<j-input
style="width: 105%"
v-model:value="
formState.hostPort.publicHost
@ -176,12 +170,8 @@
<j-col :span="6">
<j-form-item
:name="['hostPort', 'publicPort']"
:rules="[
{
required: true,
message: '输入端口',
},
]"
:rules="rules.publicPort"
:validateFirst="true"
>
<div class="form-label"></div>
@ -598,6 +588,15 @@ const dynamicValidateForm = reactive<{ cluster: Form2[] }>({
cluster: [],
});
const rules = {
publicPort: [
{
required: true,
message: '输入端口',
}
]
}
const removeCluster = (item: Form2) => {
let index = dynamicValidateForm.cluster.indexOf(item);
if (index !== -1) {

View File

@ -14,6 +14,7 @@ ProtocolMapping.set('Ctwing', 'HTTP');
ProtocolMapping.set('modbus-tcp', 'MODBUS_TCP');
ProtocolMapping.set('opc-ua', 'OPC_UA');
ProtocolMapping.set('edge-child-device', 'EdgeGateway');
ProtocolMapping.set('collector-gateway', 'collector-gateway');
ProtocolMapping.set('official-edge-gateway', 'MQTT');
const NetworkTypeMapping = new Map();

View File

@ -3738,7 +3738,7 @@ 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.26:
jetlinks-ui-components@^1.0.23:
version "1.0.26"
resolved "http://registry.jetlinks.cn/jetlinks-ui-components/-/jetlinks-ui-components-1.0.26.tgz#26896c578396b09d49649ac87c3943491af3a9ae"
integrity sha512-HkLk52C6pDKe/Ca9O4w34h1/PrC7GdBUheiicPOX2V/Lc49N+WzI9wmrCd82XBm8MocPM4gAOJxNaTxY20EO9w==
@ -3753,6 +3753,21 @@ jetlinks-ui-components@^1.0.23, jetlinks-ui-components@^1.0.26:
sortablejs "^1.15.0"
vuedraggable "^4.1.0"
jetlinks-ui-components@^1.0.27:
version "1.0.27"
resolved "http://registry.jetlinks.cn/jetlinks-ui-components/-/jetlinks-ui-components-1.0.27.tgz#97f04cb18906ad603de2bcbc62fa4b6673a7a3d0"
integrity sha512-R9dPrRMwV5imqV0JTkHeTMT8LeCnv7+Vb1IqKNIqc9I7joFZ9hLtEAE0EXO5GxTthPUiMZlQ+BDsd9ehCArO3Q==
dependencies:
"@vueuse/core" "^9.12.0"
"@vueuse/router" "^9.13.0"
ant-design-vue "^3.2.15"
colorpicker-v3 "^2.10.2"
jetlinks-ui-components "^1.0.23"
lodash-es "^4.17.21"
monaco-editor "^0.40.0"
sortablejs "^1.15.0"
vuedraggable "^4.1.0"
js-cookie@^3.0.1:
version "3.0.1"
resolved "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.1.tgz"