feat: 新增插件管理

This commit is contained in:
xieyonghong 2023-04-18 20:09:48 +08:00
parent 297637f856
commit 734b8cbff9
16 changed files with 1138 additions and 42 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.5",
"jetlinks-ui-components": "^1.0.5",
"js-cookie": "^3.0.1",
"less": "^4.1.3",
"less-loader": "^11.1.0",

View File

@ -43,3 +43,7 @@ export const getResourcesCurrent = () =>
export const getClusters = () =>
server.get(`network/resources/clusters`);
export const getPluginList = (data: any) => server.post('/plugin/driver/_query/no-paging', data)
export const getPluginConfig = (id: string) => server.get(`/plugin/driver/${id}/description`)

View File

@ -24,3 +24,7 @@ export const savePluginData = (type: string, pluginId: string, internalId: strin
export const getPluginData = (type: string, pluginId: string, internalId: string ) => get(`/plugin/mapping/${type}/${pluginId}/${internalId}`)
export const getPublic = (id: string, path: string) => get(`/plugin/driver/${id}/${path}`)
export const getTypes = () => get(`/dictionary/internal-plugin-type/items`)
export const vailIdFn = (id: string ) => get(`/plugin/driver/id/_validate`, { id })

View File

@ -1,7 +1,7 @@
const MaxLengthStringFn = (len: number = 64) => ({
max: len,
message: `最多输入${64}个字符`,
message: `最多输入${len}个字符`,
})
export const Max_Length_64 = [MaxLengthStringFn()]

View File

@ -13,11 +13,19 @@
<div class="go-back" v-if="id === ':id'">
<a @click="goBack">返回</a>
</div>
<template v-if="showType === 'network'">
<Network
v-if="showType === 'network'"
v-if="provider.id !== 'plugin_gateway'"
:provider="provider"
:data="data"
/>
<Plugin
v-else
:provider="provider"
:data="data"
/>
</template>
<Media
v-if="showType === 'media'"
:provider="provider"
@ -52,6 +60,7 @@ import Media from '../components/Media/index.vue';
import Channel from '../components/Channel/index.vue';
import Edge from '../components/Edge/index.vue';
import Cloud from '../components/Cloud/index.vue';
import Plugin from '../components/Plugin/index.vue'
import { getProviders, detail } from '@/api/link/accessConfig';
import { accessConfigTypeFilter } from '@/utils/setting';
@ -125,14 +134,8 @@ const getTypeList = (result: Record<string, any>) => {
edge.push(item);
} else {
item.type = 'network';
// network.push(item);
/**
* 插件设备接入 暂时不开发 todo
*/
if (item.id !== 'plugin_gateway' || item.name !== '插件设备接入') {
network.push(item);
}
}
});
network.length &&

View File

@ -34,8 +34,8 @@ const emit = defineEmits(['checkedChange']);
const props = defineProps({
checked: {
type: Array,
default: () => [],
type: String,
default: undefined,
},
data: {
type: Object,
@ -115,15 +115,15 @@ const checkedChange = (id: string) => {
}
}
.access-media {
background: url('/public/images/access-media.png') no-repeat;
background: url('/images/access-media.png') no-repeat;
background-position: bottom right;
}
.access-network {
background: url('/public/images/access-network.png') no-repeat;
.access-network, .access-plugin {
background: url('/images/access-network.png') no-repeat;
background-position: bottom right;
}
.access-protocol {
background: url('/public/images/access-protocol.png') no-repeat;
background: url('/images/access-protocol.png') no-repeat;
background-position: bottom right;
}
</style>

View File

@ -294,6 +294,7 @@
:hasPermission="`link/AccessConfig:${
id === ':id' ? 'add' : 'update'
}`"
:loading='loading'
>
保存
</PermissionButton>
@ -378,6 +379,7 @@ const formData = ref({
name: '',
description: '',
});
const loading = ref(false)
const { resetFields, validate, validateInfos } = useForm(
formData,
@ -515,10 +517,12 @@ const saveData = () => {
? 'Gateway'
: ProtocolMapping.get(props.provider.id),
};
loading.value = true
const resp =
id === ':id'
? await save(params)
: await update({ ...params, id });
loading.value = false
if (resp.status === 200) {
onlyMessage('操作成功', 'success');
history.back();

View File

@ -0,0 +1,427 @@
<template>
<div>
<j-steps :current="current">
<j-step disabled :key="0" title="选择插件" />
<j-step disabled :key="1" title="完成" />
</j-steps>
<div class='steps-content'>
<div class="steps-box" v-if="current === 0">
<div class="search">
<j-input-search
allowClear
placeholder="请输入"
style="width: 300px"
@search="pluginSearch"
/>
<PermissionButton
type="primary"
@click="addPlugin"
hasPermission="link/plugin:add"
>
<template #icon><AIcon type="PlusOutlined" /></template>
新增
</PermissionButton>
</div>
<j-scrollbar height="480">
<j-row
:gutter="[24, 24]"
style="width: 100%"
v-if="pluginList.length > 0"
>
<j-col
:span="8"
v-for="item in pluginList"
:key="item.id"
>
<AccessCard
@checkedChange="AccessChange"
:checked="AccessCurrent"
:disabled='paramsId !== ":id"'
:data="{ ...item, type: 'plugin' }"
>
<template #other>
<div class='plugin-other'>
<div class='plugin-id'>
插件ID
<div class='other-content'>
<Ellipsis >
{{ item.id }}
</Ellipsis>
</div>
</div>
<div class='plugin-version'>
版本号
<div class='other-content'>
<Ellipsis >
{{ item.version }}
</Ellipsis>
</div>
</div>
</div>
</template>
</AccessCard>
</j-col>
</j-row>
<j-empty
style="margin-top: 10%"
v-else
description="暂无数据"
/>
</j-scrollbar>
</div>
<div class="steps-box" v-else-if="current === 1">
<div
class="card-last"
:style="`max-height:${ clientHeight > 900 ? 750 : clientHeight * 0.7 }px`"
>
<j-row :gutter="[24, 24]">
<j-col :span="16">
<title-component data="基本信息" />
<j-form
ref="formRef"
:model="formData"
layout="vertical"
>
<j-form-item
label="名称"
:rules="[
{ required: true, message: '请输入名称', trigger: 'blur' },
{
max: 64,
message: '最多可输入64个字符',
trigger: 'blur',
},
]"
name='name'
>
<j-input
v-model:value="formData.name"
allowClear
placeholder="请输入名称"
/>
</j-form-item>
<j-form-item
label="说明"
:rules="[{ max: 200, message: '最多可输入200个字符' }]"
name='description'
>
<j-textarea
placeholder="请输入说明"
:rows="4"
v-model:value="formData.description"
show-count
:maxlength="200"
/>
</j-form-item>
<template v-if='config.length' >
<title-component data="通用配置" />
<j-form-item
v-for='item in config'
:key='item.name'
:name='["configuration", item.name]'
:label='item.label'
:rules='item.rules'
>
<ValueItem v-model:modelValue='formData.configuration[item.name]' :itemType='item.type' />
</j-form-item>
</template>
</j-form>
</j-col>
</j-row>
</div>
</div>
</div>
<div class="steps-action">
<j-button
v-if="current === 0"
type="primary"
style="margin-right: 8px"
@click="next"
>
下一步
</j-button>
<PermissionButton
v-if="current === 1 && view === 'false'"
type="primary"
style="margin-right: 8px"
@click="saveData"
:hasPermission="`link/AccessConfig:${
id === ':id' ? 'add' : 'update'
}`"
:loading='loading'
>
保存
</PermissionButton>
<j-button
v-if="current > 0"
@click="prev"
>
上一步
</j-button>
</div>
</div>
</template>
<script lang='ts' setup name='AccessConfigPlugin'>
import {
save,
update,
getPluginList,
getPluginConfig } from '@/api/link/accessConfig'
import AccessCard from '../AccessCard/index.vue';
import { useMenuStore } from 'store/menu'
import { onlyMessage } from '@/utils/comm';
const props = defineProps({
provider: {
type: Object,
default: () => {},
},
data: {
type: Object,
default: () => {},
},
});
const route = useRoute();
const menuStory = useMenuStore();
const current = ref(0);
const pluginList = ref([])
const AccessCurrent = ref(props.data.channelId)
const paramsId = route.params.id as string;
const view = route.query.view as string;
const clientHeight = document.body.clientHeight;
const loading = ref(false)
const formData = reactive({
name: undefined,
description: undefined,
configuration: {}
})
const formRef = ref();
const config = ref<any>([])
const queryPlugin = (params = {}) => {
getPluginList({
...params,
paging: false
}).then(res => {
pluginList.value = []
if (res.success) {
pluginList.value = res.result || []
}
})
}
const getRules = (item: any) => {
let typeName = '输入'
if (['select', 'date'].includes(item.type?.type || 'string')) {
typeName = '选择'
}
const rules = [
{
required: true,
message: `${typeName}${item.name}`
}
]
if (['select', 'date'].includes(item.type?.type || 'string')) {
rules.push({
max: 64,
message: `最多输入64个字符`
})
}
return rules
}
const queryPluginConfig = (id: string, update: boolean = true) => {
getPluginConfig(id).then(res => {
if (res.success) {
const properties = res.result?.others?.configMetadata?.properties || []
config.value = properties.map((item: any) => {
if (update) {
formData.configuration[item.property] = undefined
}
return {
label: item.name,
name: item.property,
type: item.type?.type || 'string',
rules: getRules(item)
}
})
}
})
}
const pluginSearch = (val: string) => {
queryPlugin({
terms: [{
column: 'name',
termType: 'like',
value: `%${val}%`
}]
})
}
const AccessChange = (id: string) => {
if (!props.data.id) {
AccessCurrent.value = id;
}
};
const addPlugin = () => {
const url = menuStory.menus['link/plugin']?.path;
const wd: any = window.open(
`${window.location.origin + window.location.pathname}#${url}?save=true`,
);
wd.onTabSaveSuccess = (value: any) => {
if (value.success) {
AccessCurrent.value = value.result?.id;
pluginList.value.unshift(value.result as any)
}
}
}
/**
* 下一步
*/
const next = () => {
if (!AccessCurrent.value) {
return onlyMessage('请选择插件!', 'error');
}
current.value += 1
}
/**
* 上一步
*/
const prev = () => {
current.value -= 1
}
/**
* 保存
*/
const saveData = () => {
formRef.value.validate().then(async (data: any) => {
if (data) {
const params = {
...props.data,
...data,
protocol: 'plugin',
channel: 'plugin', //
channelId: AccessCurrent.value,
provider: props.provider.id,
transport: 'plugin'
};
loading.value = true
const resp =
paramsId === ':id'
? await save(params)
: await update({ ...params, id: paramsId });
loading.value = false
if (resp.status === 200) {
onlyMessage('操作成功', 'success');
history.back();
if ((window as any).onTabSaveSuccess) {
if (resp.result?.id) {
(window as any).onTabSaveSuccess(resp);
setTimeout(() => window.close(), 300);
}
}
}
}
})
}
watchEffect(() => {
if (current.value === 1 && AccessCurrent.value) {
queryPluginConfig(AccessCurrent.value, AccessCurrent.value !== props.data.channelId)
}
})
onMounted(() => {
if (paramsId !== ':id') { //
formData.name = props.data.name
formData.description = props.data.description
formData.configuration = props.data.configuration
}
})
queryPlugin()
</script>
<style scoped lang='less'>
.steps-content {
margin-top: 20px;
}
.steps-box {
min-height: 400px;
.card-last {
padding-right: 5px;
overflow-y: auto;
overflow-x: hidden;
}
}
.steps-action {
width: 100%;
margin-top: 24px;
}
.alert {
height: 40px;
padding-left: 10px;
color: rgba(0, 0, 0, 0.55);
line-height: 40px;
background-color: #f6f6f6;
}
.search {
display: flex;
margin: 15px 0;
justify-content: space-between;
}
.other {
width: 100%;
height: 20px;
display: flex;
align-items: center;
justify-content: center;
.item {
width: 100%;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
.plugin-other {
display: flex;
gap: 16px;
.plugin-id, .plugin-version {
color: rgba(0, 0, 0, 0.85);
opacity: .45;
display: flex;
}
.plugin-id {
width: 50%;
.other-content {
display: flex;
width: 0;
flex-grow: 1;
}
}
}
</style>

View File

@ -33,6 +33,7 @@ BackMap.set('modbus-tcp', getImage('/access/modbus.png'));
BackMap.set('coap-server-gateway', getImage('/access/coap.png'));
BackMap.set('tcp-server-gateway', getImage('/access/tcp.png'));
BackMap.set('Ctwing', getImage('/access/ctwing.png'));
BackMap.set('plugin_gateway', getImage('/access/plugin.png'));
BackMap.set('child-device', getImage('/access/child-device.png'));
BackMap.set('opc-ua', getImage('/access/opc-ua.png'));
BackMap.set('http-server-gateway', getImage('/access/http.png'));

View File

@ -13,18 +13,7 @@
:columns="columns"
:request="list"
:defaultParams="{
sorts: [{ name: 'createTime', order: 'desc' }],
terms: [
{
terms: [
{
termType: 'nin',
column: 'provider',
value: 'plugin_gateway', //todo
},
],
},
],
sorts: [{ name: 'createTime', order: 'desc' }]
}"
gridColumn="2"
:gridColumns="[1, 2]"

View File

@ -0,0 +1,172 @@
<template>
<j-modal
:maskClosable='false'
:visible='true'
:title="!!data?.id ? '编辑' : '新增'"
:confirmLoading='loading'
@ok='handleSave'
@cancel='handleCancel'
width='650px'
>
<div>
<j-form :layout="'vertical'" ref='formRef' :model='modelRef'>
<j-form-item
name='id'
:rules='IdRules'
>
<template #label>
<span>
插件ID
<j-tooltip
title='若不填写系统将自动生成唯一ID'
>
<AIcon
type='QuestionCircleOutlined'
style='margin-left: 2px'
/>
</j-tooltip>
</span>
</template>
<j-input v-model:value='modelRef.id' :disabled='!!data.id' />
</j-form-item>
<j-form-item
label='插件名称'
name='name'
:rules="nameRules"
>
<j-input v-model:value='modelRef.name' />
</j-form-item>
<j-form-item
label='文件'
name='version'
:rules='[{ required: true, message: "请上传文件" }]'
>
<UploadFile v-model:modelValue='modelRef.version' @change='uploadChange' :disabled='data.id' />
</j-form-item>
<div v-if='modelRef.version' class='file-detail'>
<div>
<span>插件类型</span>
<span class='file-detail-item'>{{ TypeMap[modelRef.type] }}</span>
</div>
<div>
<span>版本</span>
<span class='file-detail-item'>{{ modelRef.version }}</span>
</div>
</div>
<j-form-item
label='说明'
name='describe'
:rules='Max_Length_200'
>
<j-textarea
v-model:value='modelRef.description'
placeholder='请输入说明'
showCount
:maxlength='200'
/>
</j-form-item>
</j-form>
</div>
</j-modal>
</template>
<script setup lang='ts' name='PluginSave'>
import { ID_Rule, Max_Length_64, Max_Length_200, RequiredStringFn } from '@/components/Form/rules'
import UploadFile from './UploadFile.vue'
import { FileUploadResult } from '@/views/link/plugin/typings'
import { add, vailIdFn } from '@/api/link/plugin'
import { message } from 'jetlinks-ui-components'
import { TypeMap } from './util'
import { start } from '@/api/link/type'
const props = defineProps({
data: {
type: Object,
default: () => ({})
}
})
const emit = defineEmits(['cancel', 'ok'])
const route = useRoute()
const formRef = ref()
const fileType = ref(props.data.type)
const loading = ref(false)
const vailId = async (_: any, value: string) => {
if (!!props.data.id && value) { //
const resp = await vailIdFn(value)
if (resp.success && resp.result) {
return Promise.reject('ID重复');
}
}
return Promise.resolve();
}
const nameRules = [
RequiredStringFn('插件名称'),
...Max_Length_64
]
const IdRules = [
...ID_Rule,
{
validator: vailId,
trigger: 'blur',
},
]
const modelRef = reactive<any>({
id: props.data.id,
name: props.data.name,
description: props.data.description,
type: props.data.type,
provider: props.data.provider || 'jar',
version: props.data.version,
filename: props.data.filename,
configuration: props.data.configuration || {}
})
const uploadChange = (data: FileUploadResult) => {
modelRef.type = data.type.value
modelRef.filename = data.filename
modelRef.configuration.location = data.accessUrl
}
const handleSave = async () => {
const data = await formRef.value.validate()
if (data) {
loading.value = true
const resp = await add(modelRef).catch(() => { success: false })
loading.value = false
if (resp.success) {
message.success('操作成功!');
if (route.query.save && (window as any).onTabSaveSuccess) {
(window as any).onTabSaveSuccess(resp);
setTimeout(() => window.close(), 300);
return
}
emit('ok');
formRef.value.resetFields();
}
}
}
const handleCancel = () => {
emit('cancel')
}
</script>
<style scoped lang='less'>
.file-detail {
display: flex;
flex-direction: column;
gap: 16px;
margin-bottom: 16px;
.file-detail-item {
color: #4F4F4F;
}
}
</style>

View File

@ -0,0 +1,92 @@
<template>
<j-upload
name="file"
accept=".jar"
:action="uploadFile"
:headers="{
[TOKEN_KEY]: LocalStore.get(TOKEN_KEY),
}"
@change="handleChange"
class="upload-box"
:before-upload="beforeUpload"
:disabled='disabled || loading'
:maxCount='1'
>
<div>
<j-button :disabled='disabled'>上传文件</j-button>
<span class='upload-tip'>格式要求{文件名}.jar</span>
</div>
</j-upload>
</template>
<script setup lang="ts" name="FileUpload">
import { LocalStore } from '@/utils/comm';
import { TOKEN_KEY } from '@/utils/variable';
import { uploadFile } from '@/api/link/plugin';
import { onlyMessage } from '@/utils/comm';
import type { UploadChangeParam, UploadProps } from 'ant-design-vue';
import { notification as Notification } from 'jetlinks-ui-components';
import { useSystem } from '@/store/system';
const emit = defineEmits(['update:modelValue', 'change']);
const props = defineProps({
modelValue: {
type: String,
default: () => '',
},
disabled: {
type: Boolean,
default: false
}
});
const paths: string = useSystem().$state.configInfo.paths?.[
'base-path'
] as string;
const value = ref(props.modelValue);
const loading = ref(false);
const beforeUpload: UploadProps['beforeUpload'] = (file, fl) => {
const arr = file.name.split('.');
const isFile = ['jar'].includes(arr[arr.length - 1]); // file.type === 'application/zip' || file.type === 'application/javj-archive'
if (!isFile) {
onlyMessage('请上传.jar格式的文件', 'error');
loading.value = false;
}
return isFile;
};
const handleChange = async (info: UploadChangeParam) => {
loading.value = true;
if (info.file.status === 'done') {
loading.value = false;
console.log(info.file)
const result = info.file.response?.result;
const f = result.accessUrl;
onlyMessage('上传成功!', 'success');
value.value = f;
emit('update:modelValue', result.version);
emit('change', result);
} else {
if (info.file.error) {
Notification.error({
// key: '403',
message: '系统提示',
description: '系统未知错误,请反馈给管理员',
});
loading.value = false;
} else if (info.file.response) {
loading.value = false;
}
}
};
</script>
<style lang="less" scoped>
.upload-tip {
color: #999;
padding-left: 12px;
}
</style>

View File

@ -0,0 +1,263 @@
<template>
<page-container>
<pro-search
:columns="columns"
target="link-plugin"
@search="handleSearch"
/>
<FullPage>
<JProTable
ref="instanceRef"
:columns="columns"
:request="queryPage"
:defaultParams="{sorts: [{ name: 'createTime', order: 'desc' }]}"
:params='params'
>
<template #headerTitle>
<PermissionButton
type="primary"
@click="handleAdd"
hasPermission="link/plugin:add"
>
<template #icon><AIcon type="PlusOutlined" /></template>
新增
</PermissionButton>
</template>
<template #card="slotProps">
<CardBox
:value="slotProps"
:showStatus='false'
:actions='getActions(slotProps)'
status='processing'
>
<template #img>
<img
:width="80"
:height="80"
:src="getImage('/plug.png')"
/>
</template>
<template #content>
<Ellipsis style="width: calc(100% - 100px); margin-bottom: 18px;">
<span style="font-size: 16px; font-weight: 600">
{{ slotProps.name }}
</span>
</Ellipsis>
<j-row>
<j-col :span="12">
<div class="card-item-content-text">
插件ID
</div>
<Ellipsis style="width: 100%">
{{ slotProps.id }}
</Ellipsis>
</j-col>
<j-col :span="12">
<div class="card-item-content-text">
插件类型
</div>
<Ellipsis style="width: 100%">
{{ TypeMap[slotProps.type] }}
</Ellipsis>
</j-col>
</j-row>
</template>
<template #actions="item">
<PermissionButton
:disabled="item.disabled"
:popConfirm="item.popConfirm"
:tooltip="{
...item.tooltip,
}"
@click="item.onClick"
:hasPermission="'link/plugin:' + item.key"
>
<AIcon
type="DeleteOutlined"
v-if="item.key === 'delete'"
/>
<template v-else>
<AIcon :type="item.icon" />
<span>{{ item?.text }}</span>
</template>
</PermissionButton>
</template>
</CardBox>
</template>
<template #type='slotProps'>
<span>{{ TypeMap[slotProps.type] }}</span>
</template>
<template #action="slotProps">
<j-space>
<template
v-for="i in getActions(slotProps)"
:key="i.key"
>
<PermissionButton
:disabled="i.disabled"
:popConfirm="i.popConfirm"
:tooltip="{
...i.tooltip,
}"
@click="i.onClick"
type="link"
:danger="i.key === 'delete'"
style="padding: 0 5px"
:hasPermission="'link/plugin:' + i.key"
>
<template #icon><AIcon :type="i.icon" /></template>
</PermissionButton>
</template>
</j-space>
</template>
</JProTable>
</FullPage>
</page-container>
<SaveModal
v-if='visible'
:data='editData'
@cancel='cancel'
@ok='save'
/>
</template>
<script setup lang='ts' name='PluginIndex'>
import SaveModal from './Save.vue'
import { getImage } from '@/utils/comm'
import { queryPage, removeFn, getTypes } from '@/api/link/plugin'
import { message } from 'jetlinks-ui-components'
import { TypeMap } from './util'
const route = useRoute()
const visible = ref(false)
const params = ref<any>()
const editData = ref()
const instanceRef = ref()
const columns = [
{
title: 'ID',
dataIndex: 'id',
key: 'type',
fixed: 'left',
width: 200,
ellipsis: true,
search: {
type: 'input',
},
},
{
title: '插件名称',
dataIndex: 'name',
key: 'type',
fixed: 'left',
width: 200,
ellipsis: true,
search: {
type: 'input',
},
},
{
title: '插件类型',
dataIndex: 'type',
key: 'type',
scopedSlots: true,
search: {
type: 'select',
options: () => {
return new Promise(resolve => {
getTypes().then(res => {
resolve(res.result?.map(item => ({ ...item, label: item.text })))
})
})
}
},
},
{
title: '说明',
dataIndex: 'description',
key: 'description',
ellipsis: true,
search: {
type: 'string',
},
},
{
title: '操作',
key: 'action',
fixed: 'right',
width: 120,
scopedSlots: true,
},
]
const handleAdd = () => {
visible.value = true
}
const handleSearch = (p: any) => {
params.value = p
}
const save = () => {
if (instanceRef.value) {
instanceRef.value?.reload();
}
visible.value = false
}
const cancel = () => {
visible.value = false
editData.value = undefined
}
const getActions = (data: any) => {
return [
{
key: 'update',
text: '编辑',
tooltip: {
title: '编辑',
},
icon: 'EditOutlined',
onClick: () => {
visible.value = true;
editData.value = data;
},
},
{
key: 'delete',
text: '删除',
tooltip: {
title: '删除',
},
popConfirm: {
title: '确认删除?',
onConfirm: async () => {
const resp = await removeFn(data.id);
if (resp.status === 200) {
message.success('操作成功!');
instanceRef.value?.reload();
} else {
message.error('操作失败!');
}
},
},
icon: 'DeleteOutlined',
},
]
}
onMounted(() => {
if (route.query.save) {
visible.value = true
}
})
</script>
<style scoped>
</style>

View File

@ -0,0 +1,16 @@
export type FileUploadResult = {
id: string
name: string
description: string
version: string
type: {
text: string
value: string
}
accessUrl: string
filename: string
extension: string
length: string
md5: string
sha256: string
}

View File

@ -0,0 +1,4 @@
export const TypeMap = {
'deviceGateway': '设备接入网关',
'thingsManager': '物管理',
}

139
yarn.lock
View File

@ -1102,6 +1102,16 @@
estree-walker "^2.0.2"
source-map "^0.6.1"
"@vue/compiler-core@3.2.47":
version "3.2.47"
resolved "https://registry.jetlinks.cn/@vue%2fcompiler-core/-/compiler-core-3.2.47.tgz#3e07c684d74897ac9aa5922c520741f3029267f8"
integrity sha512-p4D7FDnQb7+YJmO2iPEv0SQNeNzcbHdGByJDsT4lynf63AFkOTFN07HsiRSvjGo0QrxR/o3d0hUyNCUnBU2Tig==
dependencies:
"@babel/parser" "^7.16.4"
"@vue/shared" "3.2.47"
estree-walker "^2.0.2"
source-map "^0.6.1"
"@vue/compiler-dom@3.2.45", "@vue/compiler-dom@^3.2.45":
version "3.2.45"
resolved "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.45.tgz"
@ -1110,6 +1120,14 @@
"@vue/compiler-core" "3.2.45"
"@vue/shared" "3.2.45"
"@vue/compiler-dom@3.2.47":
version "3.2.47"
resolved "https://registry.jetlinks.cn/@vue%2fcompiler-dom/-/compiler-dom-3.2.47.tgz#a0b06caf7ef7056939e563dcaa9cbde30794f305"
integrity sha512-dBBnEHEPoftUiS03a4ggEig74J2YBZ2UIeyfpcRM2tavgMWo4bsEfgCGsu+uJIL/vax9S+JztH8NmQerUo7shQ==
dependencies:
"@vue/compiler-core" "3.2.47"
"@vue/shared" "3.2.47"
"@vue/compiler-sfc@3.2.45", "@vue/compiler-sfc@^3.2.29", "@vue/compiler-sfc@^3.2.45":
version "3.2.45"
resolved "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.45.tgz"
@ -1126,6 +1144,22 @@
postcss "^8.1.10"
source-map "^0.6.1"
"@vue/compiler-sfc@3.2.47":
version "3.2.47"
resolved "https://registry.jetlinks.cn/@vue%2fcompiler-sfc/-/compiler-sfc-3.2.47.tgz#1bdc36f6cdc1643f72e2c397eb1a398f5004ad3d"
integrity sha512-rog05W+2IFfxjMcFw10tM9+f7i/+FFpZJJ5XHX72NP9eC2uRD+42M3pYcQqDXVYoj74kHMSEdQ/WmCjt8JFksQ==
dependencies:
"@babel/parser" "^7.16.4"
"@vue/compiler-core" "3.2.47"
"@vue/compiler-dom" "3.2.47"
"@vue/compiler-ssr" "3.2.47"
"@vue/reactivity-transform" "3.2.47"
"@vue/shared" "3.2.47"
estree-walker "^2.0.2"
magic-string "^0.25.7"
postcss "^8.1.10"
source-map "^0.6.1"
"@vue/compiler-ssr@3.2.45":
version "3.2.45"
resolved "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.45.tgz"
@ -1134,6 +1168,14 @@
"@vue/compiler-dom" "3.2.45"
"@vue/shared" "3.2.45"
"@vue/compiler-ssr@3.2.47":
version "3.2.47"
resolved "https://registry.jetlinks.cn/@vue%2fcompiler-ssr/-/compiler-ssr-3.2.47.tgz#35872c01a273aac4d6070ab9d8da918ab13057ee"
integrity sha512-wVXC+gszhulcMD8wpxMsqSOpvDZ6xKXSVWkf50Guf/S+28hTAXPDYRTbLQ3EDkOP5Xz/+SY37YiwDquKbJOgZw==
dependencies:
"@vue/compiler-dom" "3.2.47"
"@vue/shared" "3.2.47"
"@vue/devtools-api@^6.4.5":
version "6.4.5"
resolved "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.4.5.tgz"
@ -1150,6 +1192,17 @@
estree-walker "^2.0.2"
magic-string "^0.25.7"
"@vue/reactivity-transform@3.2.47":
version "3.2.47"
resolved "https://registry.jetlinks.cn/@vue%2freactivity-transform/-/reactivity-transform-3.2.47.tgz#e45df4d06370f8abf29081a16afd25cffba6d84e"
integrity sha512-m8lGXw8rdnPVVIdIFhf0LeQ/ixyHkH5plYuS83yop5n7ggVJU+z5v0zecwEnX7fa7HNLBhh2qngJJkxpwEEmYA==
dependencies:
"@babel/parser" "^7.16.4"
"@vue/compiler-core" "3.2.47"
"@vue/shared" "3.2.47"
estree-walker "^2.0.2"
magic-string "^0.25.7"
"@vue/reactivity@3.2.45", "@vue/reactivity@^3.2.45":
version "3.2.45"
resolved "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.45.tgz"
@ -1157,6 +1210,13 @@
dependencies:
"@vue/shared" "3.2.45"
"@vue/reactivity@3.2.47":
version "3.2.47"
resolved "https://registry.jetlinks.cn/@vue%2freactivity/-/reactivity-3.2.47.tgz#1d6399074eadfc3ed35c727e2fd707d6881140b6"
integrity sha512-7khqQ/75oyyg+N/e+iwV6lpy1f5wq759NdlS1fpAhFXa8VeAIKGgk2E/C4VF59lx5b+Ezs5fpp/5WsRYXQiKxQ==
dependencies:
"@vue/shared" "3.2.47"
"@vue/runtime-core@3.2.45":
version "3.2.45"
resolved "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.2.45.tgz"
@ -1165,6 +1225,14 @@
"@vue/reactivity" "3.2.45"
"@vue/shared" "3.2.45"
"@vue/runtime-core@3.2.47":
version "3.2.47"
resolved "https://registry.jetlinks.cn/@vue%2fruntime-core/-/runtime-core-3.2.47.tgz#406ebade3d5551c00fc6409bbc1eeb10f32e121d"
integrity sha512-RZxbLQIRB/K0ev0K9FXhNbBzT32H9iRtYbaXb0ZIz2usLms/D55dJR2t6cIEUn6vyhS3ALNvNthI+Q95C+NOpA==
dependencies:
"@vue/reactivity" "3.2.47"
"@vue/shared" "3.2.47"
"@vue/runtime-dom@3.2.45":
version "3.2.45"
resolved "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.2.45.tgz"
@ -1174,6 +1242,15 @@
"@vue/shared" "3.2.45"
csstype "^2.6.8"
"@vue/runtime-dom@3.2.47":
version "3.2.47"
resolved "https://registry.jetlinks.cn/@vue%2fruntime-dom/-/runtime-dom-3.2.47.tgz#93e760eeaeab84dedfb7c3eaf3ed58d776299382"
integrity sha512-ArXrFTjS6TsDei4qwNvgrdmHtD930KgSKGhS5M+j8QxXrDJYLqYw4RRcDy1bz1m1wMmb6j+zGLifdVHtkXA7gA==
dependencies:
"@vue/runtime-core" "3.2.47"
"@vue/shared" "3.2.47"
csstype "^2.6.8"
"@vue/server-renderer@3.2.45":
version "3.2.45"
resolved "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.2.45.tgz"
@ -1182,11 +1259,24 @@
"@vue/compiler-ssr" "3.2.45"
"@vue/shared" "3.2.45"
"@vue/server-renderer@3.2.47":
version "3.2.47"
resolved "https://registry.jetlinks.cn/@vue%2fserver-renderer/-/server-renderer-3.2.47.tgz#8aa1d1871fc4eb5a7851aa7f741f8f700e6de3c0"
integrity sha512-dN9gc1i8EvmP9RCzvneONXsKfBRgqFeFZLurmHOveL7oH6HiFXJw5OGu294n1nHc/HMgTy6LulU/tv5/A7f/LA==
dependencies:
"@vue/compiler-ssr" "3.2.47"
"@vue/shared" "3.2.47"
"@vue/shared@3.2.45", "@vue/shared@^3.2.45":
version "3.2.45"
resolved "https://registry.npmjs.org/@vue/shared/-/shared-3.2.45.tgz"
integrity sha512-Ewzq5Yhimg7pSztDV+RH1UDKBzmtqieXQlpTVm2AwraoRL/Rks96mvd8Vgi7Lj+h+TH8dv7mXD3FRZR3TUvbSg==
"@vue/shared@3.2.47":
version "3.2.47"
resolved "https://registry.jetlinks.cn/@vue%2fshared/-/shared-3.2.47.tgz#e597ef75086c6e896ff5478a6bfc0a7aa4bbd14c"
integrity sha512-BHGyyGN3Q97EZx0taMQ+OLNuZcW3d37ZEVmEAyeoA9ERdGvm9Irc/0Fua8SNyOtV1w6BS4q25wbMzJujO9HIfQ==
"@vuemap/layer-3dtiles@^0.0.3":
version "0.0.3"
resolved "https://registry.npmjs.org/@vuemap/layer-3dtiles/-/layer-3dtiles-0.0.3.tgz"
@ -1217,13 +1307,13 @@
"@vueuse/core@^7.5.5":
version "7.7.1"
resolved "https://registry.jetlinks.cn/@vueuse%2fcore/-/core-7.7.1.tgz"
resolved "https://registry.jetlinks.cn/@vueuse%2fcore/-/core-7.7.1.tgz#fc284f4103de73c7fb79bc06579d8066790db511"
integrity sha512-PRRgbATMpoeUmkCEBtUeJgOwtew8s+4UsEd+Pm7MhkjL2ihCNrSqxNVtM6NFE4uP2sWnkGcZpCjPuNSxowJ1Ow==
dependencies:
"@vueuse/shared" "7.7.1"
vue-demi "*"
"@vueuse/core@^9.10.0", "@vueuse/core@^9.12.0":
"@vueuse/core@^9.10.0":
version "9.12.0"
resolved "https://registry.npmmirror.com/@vueuse/core/-/core-9.12.0.tgz"
integrity sha512-h/Di8Bvf6xRcvS/PvUVheiMYYz3U0tH3X25YxONSaAUBa841ayMwxkuzx/DGUMCW/wHWzD8tRy2zYmOC36r4sg==
@ -1233,14 +1323,29 @@
"@vueuse/shared" "9.12.0"
vue-demi "*"
"@vueuse/core@^9.12.0":
version "9.13.0"
resolved "https://registry.jetlinks.cn/@vueuse%2fcore/-/core-9.13.0.tgz#2f69e66d1905c1e4eebc249a01759cf88ea00cf4"
integrity sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==
dependencies:
"@types/web-bluetooth" "^0.0.16"
"@vueuse/metadata" "9.13.0"
"@vueuse/shared" "9.13.0"
vue-demi "*"
"@vueuse/metadata@9.12.0":
version "9.12.0"
resolved "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-9.12.0.tgz"
integrity sha512-9oJ9MM9lFLlmvxXUqsR1wLt1uF7EVbP5iYaHJYqk+G2PbMjY6EXvZeTjbdO89HgoF5cI6z49o2zT/jD9SVoNpQ==
"@vueuse/metadata@9.13.0":
version "9.13.0"
resolved "https://registry.jetlinks.cn/@vueuse%2fmetadata/-/metadata-9.13.0.tgz#bc25a6cdad1b1a93c36ce30191124da6520539ff"
integrity sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ==
"@vueuse/router@^9.13.0":
version "9.13.0"
resolved "http://47.108.170.157:9013/@vueuse%2frouter/-/router-9.13.0.tgz#cfc757fa89c654ab749c60bc2445f945cbb86b32"
resolved "https://registry.jetlinks.cn/@vueuse%2frouter/-/router-9.13.0.tgz#cfc757fa89c654ab749c60bc2445f945cbb86b32"
integrity sha512-lcL6auSUGMGZMdDzZJb02QDe909AChzMXoxqFS3gL2E8mHmIx0SrNor+33UkqvvBPi18vXpDq/R7tPd9fxWwTg==
dependencies:
"@vueuse/shared" "9.13.0"
@ -1248,7 +1353,7 @@
"@vueuse/shared@7.7.1":
version "7.7.1"
resolved "https://registry.jetlinks.cn/@vueuse%2fshared/-/shared-7.7.1.tgz"
resolved "https://registry.jetlinks.cn/@vueuse%2fshared/-/shared-7.7.1.tgz#77e312de7275380efce86b0079bd7938791a076b"
integrity sha512-rN2qd22AUl7VdBxihagWyhUNHCyVk9IpvBTTfHoLH9G7rGE552X1f+zeCfehuno0zXif13jPw+icW/wn2a0rnQ==
dependencies:
vue-demi "*"
@ -1262,7 +1367,7 @@
"@vueuse/shared@9.13.0":
version "9.13.0"
resolved "http://47.108.170.157:9013/@vueuse%2fshared/-/shared-9.13.0.tgz#089ff4cc4e2e7a4015e57a8f32e4b39d096353b9"
resolved "https://registry.jetlinks.cn/@vueuse%2fshared/-/shared-9.13.0.tgz#089ff4cc4e2e7a4015e57a8f32e4b39d096353b9"
integrity sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==
dependencies:
vue-demi "*"
@ -2065,7 +2170,7 @@ colorette@^2.0.16, colorette@^2.0.19:
colorpicker-v3@^2.10.2:
version "2.10.2"
resolved "https://registry.jetlinks.cn/colorpicker-v3/-/colorpicker-v3-2.10.2.tgz"
resolved "https://registry.jetlinks.cn/colorpicker-v3/-/colorpicker-v3-2.10.2.tgz#f5e2f9ea603eee4d227ba10fa436d86963aa2bd0"
integrity sha512-ZWPq5wcugS3NcL7DwYqVSP5mE/x45FK31olGpig+Tko5jUXk0danfEYi1Aei3lgYs+Z0zAfhbhqVuDgOdUs5Mw==
dependencies:
"@vueuse/core" "^7.5.5"
@ -3718,15 +3823,16 @@ 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.5:
jetlinks-ui-components@1.0.5, jetlinks-ui-components@^1.0.5:
version "1.0.5"
resolved "https://registry.jetlinks.cn/jetlinks-ui-components/-/jetlinks-ui-components-1.0.5.tgz#9fa4680c69471ee9abf518782faf1b4c276aa305"
integrity sha512-pFZ0ol0jjIrrIEqPOFmrS5K623QzczYVMFPf8NQ3XeSBLksW9dncgVEPa6cZZ+9jjwAgWHo2MyPGXZcY6SF8PQ==
resolved "https://registry.jetlinks.cn/jetlinks-ui-components/-/jetlinks-ui-components-1.0.5.tgz#f91a7e1e0c72addcc6f2cadb260039010c481eaf"
integrity sha512-ZcR0ukT9bZn2syyOk9lKjjZ1cHpmMBvdHuTqayZgXwq6+pZSM5nqtVMgdUu0AXQ+pL0KbWes4L0NweYSW7XJOg==
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.5"
lodash-es "^4.17.21"
monaco-editor "^0.35.0"
@ -4609,7 +4715,7 @@ moment@*, moment@^2.29.4:
monaco-editor@^0.35.0:
version "0.35.0"
resolved "https://registry.jetlinks.cn/monaco-editor/-/monaco-editor-0.35.0.tgz"
resolved "https://registry.jetlinks.cn/monaco-editor/-/monaco-editor-0.35.0.tgz#49c4220c815262a900dacf0ae8a59bef66efab8b"
integrity sha512-BJfkAZ0EJ7JgrgWzqjfBNP9hPSS8NlfECEDMEIIiozV2UaPq22yeuOjgbd3TwMh3anH0krWZirXZfn8KUSxiOA==
monaco-editor@^0.36.0:
@ -6916,7 +7022,18 @@ vue3-ts-jsoneditor@^2.7.1:
vanilla-jsoneditor "^0.7.9"
vue "^3.2.37"
vue@^3.2.25, vue@^3.2.37, vue@^3.2.45:
vue@^3.2.25:
version "3.2.47"
resolved "https://registry.jetlinks.cn/vue/-/vue-3.2.47.tgz#3eb736cbc606fc87038dbba6a154707c8a34cff0"
integrity sha512-60188y/9Dc9WVrAZeUVSDxRQOZ+z+y5nO2ts9jWXSTkMvayiWxCWOWtBQoYjLeccfXkiiPZWAHcV+WTPhkqJHQ==
dependencies:
"@vue/compiler-dom" "3.2.47"
"@vue/compiler-sfc" "3.2.47"
"@vue/runtime-dom" "3.2.47"
"@vue/server-renderer" "3.2.47"
"@vue/shared" "3.2.47"
vue@^3.2.37, vue@^3.2.45:
version "3.2.45"
resolved "https://registry.npmjs.org/vue/-/vue-3.2.45.tgz"
integrity sha512-9Nx/Mg2b2xWlXykmCwiTUCWHbWIj53bnkizBxKai1g61f2Xit700A1ljowpTIM11e3uipOeiPcSqnmBg6gyiaA==