Merge branch 'dev'
# Conflicts: # package.json # src/components/Form/rules.ts # src/style.less # vite.config.ts # yarn.lock
This commit is contained in:
commit
4d9263f4fa
|
@ -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.8",
|
||||
"js-cookie": "^3.0.1",
|
||||
"less": "^4.1.3",
|
||||
"less-loader": "^11.1.0",
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 4.5 KiB |
Binary file not shown.
After Width: | Height: | Size: 3.6 KiB |
Binary file not shown.
After Width: | Height: | Size: 4.0 KiB |
Binary file not shown.
After Width: | Height: | Size: 4.0 KiB |
|
@ -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`)
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
import { post, get, remove, patch } from '@/utils/request'
|
||||
import { BASE_API_PATH } from '@/utils/variable';
|
||||
|
||||
export const queryPage = (data: any) => post(`/plugin/driver/_query`, data)
|
||||
|
||||
export const uploadFile = `${BASE_API_PATH}/plugin/driver/upload`
|
||||
|
||||
export const add = (data: any) => post('/plugin/driver', data)
|
||||
|
||||
export const removeFn = (id: string) => remove(`/plugin/driver/${id}`)
|
||||
|
||||
export const detail = (id: string) => get(`/plugin/driver/${id}`)
|
||||
|
||||
/**
|
||||
* 获取插件支持的产品信息
|
||||
* 用于在产品选择接入方式后,选择产品类型。
|
||||
* 即将平台中当前产品与插件中指定的产品绑定,然后把插件的物模型保存到产品并且绑定产品ID映射关系
|
||||
* @param id
|
||||
*/
|
||||
export const getProductsById = (id: string) => get(`/plugin/driver/${id}/products`)
|
||||
|
||||
export const savePluginData = (type: string, pluginId: string, internalId: string, externalId: string ) => patch(`/plugin/mapping/${type}/${pluginId}/${internalId}`, externalId)
|
||||
|
||||
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 })
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
const MaxLengthStringFn = (len: number = 64) => ({
|
||||
max: len,
|
||||
message: `最多输入${64}个字符`,
|
||||
message: `最多输入${len}个字符`,
|
||||
})
|
||||
|
||||
export const Max_Length_64 = [MaxLengthStringFn()]
|
||||
|
@ -25,3 +25,66 @@ export const ID_Rule = [
|
|||
},
|
||||
Max_Length_64[0]
|
||||
]
|
||||
|
||||
export const CreteRuleByType = (type: string) => {
|
||||
switch (type){
|
||||
case 'int':
|
||||
return [
|
||||
{
|
||||
validator: (_: any, value: number) => {
|
||||
const baseNumber = 2147483648
|
||||
if (value < -baseNumber) {
|
||||
return Promise.reject(`最小仅输入-${baseNumber}`);
|
||||
}
|
||||
if (value > baseNumber) {
|
||||
return Promise.reject(`最大可输入${baseNumber}`);
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
]
|
||||
case'long':
|
||||
return [
|
||||
{
|
||||
validator: (_: any, value: number) => {
|
||||
const baseNumber = 340282346638528860000000000000000000000
|
||||
if (value < -baseNumber) {
|
||||
return Promise.reject(`最小仅输入-${baseNumber}`);
|
||||
}
|
||||
if (value > baseNumber) {
|
||||
return Promise.reject(`最大可输入${baseNumber}`);
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
]
|
||||
case'float':
|
||||
return [
|
||||
{
|
||||
validator: (_: any, value: number) => {
|
||||
const baseNumber = 9223372036854775807
|
||||
if (value < -baseNumber) {
|
||||
return Promise.reject(`最小仅输入-${baseNumber}`);
|
||||
}
|
||||
if (value > baseNumber) {
|
||||
return Promise.reject(`最大可输入${baseNumber}`);
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
]
|
||||
// case'double':
|
||||
// return [
|
||||
// {
|
||||
// max: 1.7976931348623157,
|
||||
// message: '最大可输入64位字符'
|
||||
// }
|
||||
// ]
|
||||
case 'string':
|
||||
return [MaxLengthStringFn()];
|
||||
case 'description':
|
||||
return [MaxLengthStringFn(200)]
|
||||
default:
|
||||
return []
|
||||
}
|
||||
}
|
137
src/style.less
137
src/style.less
|
@ -1,3 +1,7 @@
|
|||
@import "./style/variable";
|
||||
|
||||
@DarkMenuItemColor: #808491 !important;
|
||||
|
||||
.ant-form-item-required:before {
|
||||
position: absolute;
|
||||
right: -12px;
|
||||
|
@ -16,20 +20,16 @@
|
|||
}
|
||||
|
||||
.ant-pro-top-nav-header {
|
||||
|
||||
.ant-menu-item {
|
||||
padding: 0 10px !important;
|
||||
&:not(:first-child) {
|
||||
margin-left: 8px;
|
||||
}
|
||||
&:hover {
|
||||
background-color: transparent;
|
||||
margin-left: 8px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ant-menu-item-selected,& .ant-menu-item-active {
|
||||
transition: background 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||
}
|
||||
.dark {
|
||||
background-color: #3F4960 !important;
|
||||
|
||||
h1,& .right-content, & .anticon-bell {
|
||||
color: #fff !important;
|
||||
|
@ -39,42 +39,111 @@
|
|||
color: rgba(#fff, 0.55) !important;
|
||||
}
|
||||
|
||||
.ant-menu-item-selected {
|
||||
& .ant-pro-menu-item-title,& .anticon {
|
||||
color: #fff !important;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-menu-item-selected,& .ant-menu-item-active {
|
||||
transition: background 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||
background: linear-gradient(0deg, rgba(#fff, 0.25) 0%, rgba(#fff, 0) 82%);
|
||||
&::after {
|
||||
left: 0;
|
||||
right: 0;
|
||||
border-bottom-color: rgba(#fff, .8);
|
||||
}
|
||||
}
|
||||
|
||||
&.light {
|
||||
background: #3F4960;
|
||||
box-shadow: 0 1px 0px 0px #E9E9E9;
|
||||
|
||||
h1,& .right-content, & .anticon-bell {
|
||||
color: #fff !important;
|
||||
}
|
||||
.ant-menu {
|
||||
background-color: #3F4960 !important;
|
||||
|
||||
.ant-menu-item-selected,& .ant-menu-item-active {
|
||||
transition: background 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||
background: linear-gradient(0deg, rgba(#fff, 0.15) 0%, rgba(#fff, 0) 82%);
|
||||
transition: background 0.3s cubic-bezier(0.645, 0.045, 0.355, 1) !important;
|
||||
}
|
||||
|
||||
.ant-menu-item-selected {
|
||||
span {
|
||||
color: #fff !important;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-menu-item {
|
||||
span{
|
||||
color: rgba(255, 255, 255, 0.55) !important;
|
||||
}
|
||||
&:hover {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
&::after {
|
||||
left: 0;
|
||||
right: 0;
|
||||
border-bottom-color: rgba(#fff, .7);
|
||||
}
|
||||
}
|
||||
|
||||
.ant-menu-item-selected,& .ant-menu-item-active {
|
||||
transition: background 0.3s cubic-bezier(0.645, 0.045, 0.355, 1) !important;
|
||||
background: linear-gradient(0deg, rgba(#fff, 0.25) 0%, rgba(#fff, 0) 82%) !important;
|
||||
&::after {
|
||||
border-bottom-color: rgba(#fff, .8);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ant-layout-sider-dark {
|
||||
background: #fff !important;
|
||||
|
||||
.ant-menu-dark {
|
||||
background: #fff !important;
|
||||
|
||||
span {
|
||||
color: @DarkMenuItemColor;
|
||||
}
|
||||
|
||||
.ant-menu-submenu-title {
|
||||
span {
|
||||
color: @DarkMenuItemColor;
|
||||
}
|
||||
|
||||
i {
|
||||
&::after {
|
||||
background-color: @DarkMenuItemColor;
|
||||
}
|
||||
|
||||
&::before {
|
||||
background-color: @DarkMenuItemColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ant-menu-sub {
|
||||
background: transparent;
|
||||
.ant-menu-item {
|
||||
span {
|
||||
color: @DarkMenuItemColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ant-menu-submenu-selected {
|
||||
.ant-menu-submenu-title {
|
||||
span {
|
||||
color: @primary-color !important;
|
||||
}
|
||||
|
||||
i {
|
||||
&::after {
|
||||
background-color: @primary-color !important;
|
||||
}
|
||||
|
||||
&::before {
|
||||
background-color: @primary-color !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
.ant-menu-item-selected {
|
||||
span {
|
||||
color: @primary-color !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ant-menu-item-selected {
|
||||
background-color: transparent !important;
|
||||
span {
|
||||
color: @primary-color !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
.ant-layout-sider {
|
||||
box-shadow: 1px 0 0 0 #E9E9E9 !important;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
<template>
|
||||
<j-modal
|
||||
:maskClosable="false"
|
||||
:visible="true"
|
||||
width="800px"
|
||||
title="导入"
|
||||
>
|
||||
<div>
|
||||
<!-- 选择产品 -->
|
||||
<div v-if='steps === 0'>
|
||||
<Product
|
||||
v-model:rowKey='importData.productId'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<template #footer>
|
||||
<j-button v-if='steps === 0' @click='cancel' >取消</j-button>
|
||||
<j-button v-if='steps !== 0' @click='prev' >上一步</j-button>
|
||||
<j-button v-if='steps !== 2' @click='next' type='primary'>下一步</j-button>
|
||||
<j-button v-if='steps === 2' @click='save' type='primary'>确认</j-button>
|
||||
</template>
|
||||
</j-modal>
|
||||
</template>
|
||||
|
||||
<script lang='ts' setup name='DeviceImport'>
|
||||
import Product from './product.vue'
|
||||
import { onlyMessage } from '@/utils/comm'
|
||||
|
||||
import { queryList } from '@/api/device/product';
|
||||
|
||||
const emit = defineEmits(['cancel', 'save']);
|
||||
|
||||
const steps = ref(0) // 步骤
|
||||
|
||||
const importData = reactive({
|
||||
productId: undefined,
|
||||
type: undefined,
|
||||
})
|
||||
|
||||
const next = () => {
|
||||
if (steps.value === 0 && !importData.productId) {
|
||||
return onlyMessage('请选择产品', 'error')
|
||||
}
|
||||
if (steps.value === 1 && !importData.type) {
|
||||
return onlyMessage('请选择导入方式', 'error')
|
||||
}
|
||||
steps.value += 1
|
||||
}
|
||||
|
||||
const prev = () => {
|
||||
if (steps.value === 2 && importData.type) {
|
||||
steps.value = 0
|
||||
} else {
|
||||
steps.value -= 1
|
||||
}
|
||||
}
|
||||
|
||||
const cancel = () => {
|
||||
emit('cancel')
|
||||
}
|
||||
|
||||
const save = () => {
|
||||
emit('save')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
|
@ -0,0 +1,254 @@
|
|||
<template>
|
||||
<j-advanced-search
|
||||
:columns="columns"
|
||||
type='simple'
|
||||
@search="handleSearch"
|
||||
class="scene-search"
|
||||
target="device-import-product"
|
||||
/>
|
||||
<j-divider style='margin: 0' />
|
||||
<j-pro-table
|
||||
model='CARD'
|
||||
:columns='columns'
|
||||
:params='params'
|
||||
:request='productQuery'
|
||||
:gridColumn='2'
|
||||
:gridColumns='[2,2,2]'
|
||||
:bodyStyle='{
|
||||
paddingRight: 0,
|
||||
paddingLeft: 0
|
||||
}'
|
||||
>
|
||||
<template #card="slotProps">
|
||||
<CardBox
|
||||
:value='slotProps'
|
||||
:active="rowKey === slotProps.id"
|
||||
:status="slotProps.state"
|
||||
:statusText="slotProps.state === 1 ? '正常' : '禁用'"
|
||||
:statusNames="{ 1: 'processing', 0: 'error', }"
|
||||
@click="handleClick"
|
||||
>
|
||||
<template #img>
|
||||
<slot name="img">
|
||||
<img width='80' height='80' :src="slotProps.photoUrl || getImage('/device-product.png')" />
|
||||
</slot>
|
||||
</template>
|
||||
<template #content>
|
||||
<div style='width: calc(100% - 100px)'>
|
||||
<Ellipsis>
|
||||
<span style="font-size: 16px;font-weight: 600" >
|
||||
{{ slotProps.name }}
|
||||
</span>
|
||||
</Ellipsis>
|
||||
</div>
|
||||
<j-row>
|
||||
<j-col :span="12">
|
||||
<div class="card-item-content-text">
|
||||
设备类型
|
||||
</div>
|
||||
<div>直连设备</div>
|
||||
</j-col>
|
||||
</j-row>
|
||||
</template>
|
||||
</CardBox>
|
||||
</template>
|
||||
</j-pro-table>
|
||||
</template>
|
||||
|
||||
<script setup lang='ts' name='Product'>
|
||||
import { getProviders, queryGatewayList, queryProductList } from '@/api/device/product'
|
||||
import { queryTree } from '@/api/device/category'
|
||||
import { getTreeData_api } from '@/api/system/department'
|
||||
import { getImage } from '@/utils/comm'
|
||||
import { accessConfigTypeFilter } from '@/utils/setting'
|
||||
|
||||
type Emit = {
|
||||
(e: 'update:rowKey', data: string): void
|
||||
(e: 'change', data: string): void
|
||||
}
|
||||
|
||||
const params = ref({})
|
||||
const props = defineProps({
|
||||
rowKey: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
})
|
||||
|
||||
const emit = defineEmits<Emit>()
|
||||
const firstFind = ref(true)
|
||||
|
||||
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: 'accessProvider',
|
||||
width: 150,
|
||||
ellipsis: true,
|
||||
hideInTable: true,
|
||||
search: {
|
||||
type: 'select',
|
||||
options: () => getProviders().then((resp: any) => {
|
||||
return accessConfigTypeFilter(resp.result || [])
|
||||
})
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '接入方式',
|
||||
dataIndex: 'accessName',
|
||||
width: 150,
|
||||
ellipsis: true,
|
||||
search: {
|
||||
type: 'select',
|
||||
options: () => queryGatewayList().then((resp: any) =>
|
||||
resp.result.map((item: any) => ({
|
||||
label: item.name, value: item.id
|
||||
}))
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '设备类型',
|
||||
dataIndex: 'deviceType',
|
||||
width: 150,
|
||||
search: {
|
||||
type: 'select',
|
||||
options: [
|
||||
{ label: '直连设备', value: 'device' },
|
||||
{ label: '网关子设备', value: 'childrenDevice' },
|
||||
{ label: '网关设备', value: 'gateway' },
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'state',
|
||||
width: '90px',
|
||||
search: {
|
||||
type: 'select',
|
||||
options: [
|
||||
{ label: '禁用', value: 0 },
|
||||
{ label: '正常', value: 1 },
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '说明',
|
||||
dataIndex: 'describe',
|
||||
ellipsis: true,
|
||||
width: 300,
|
||||
},
|
||||
{
|
||||
dataIndex: 'classifiedId',
|
||||
title: '分类',
|
||||
hideInTable: true,
|
||||
search: {
|
||||
type: 'treeSelect',
|
||||
options: () => {
|
||||
return new Promise((res => {
|
||||
queryTree({ paging: false }).then(resp => {
|
||||
res(resp.result)
|
||||
})
|
||||
}))
|
||||
},
|
||||
componentProps: {
|
||||
fieldNames: {
|
||||
label: 'name',
|
||||
value: 'id',
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
dataIndex: 'id$dim-assets',
|
||||
title: '所属组织',
|
||||
hideInTable: true,
|
||||
search: {
|
||||
type: 'treeSelect',
|
||||
options: () => new Promise((resolve) => {
|
||||
getTreeData_api({ paging: false }).then((resp: any) => {
|
||||
const formatValue = (list: any[]) => {
|
||||
return list.map((item: any) => {
|
||||
if (item.children) {
|
||||
item.children = formatValue(item.children);
|
||||
}
|
||||
return {
|
||||
...item,
|
||||
value: JSON.stringify({
|
||||
assetType: 'product',
|
||||
targets: [
|
||||
{
|
||||
type: 'org',
|
||||
id: item.id,
|
||||
},
|
||||
],
|
||||
}),
|
||||
}
|
||||
})
|
||||
}
|
||||
resolve(formatValue(resp.result) || [])
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
const handleSearch = (p: any) => {
|
||||
params.value = p
|
||||
}
|
||||
|
||||
const productQuery = async (p: any) => {
|
||||
const sorts: any = [];
|
||||
|
||||
if (props.rowKey) {
|
||||
sorts.push({
|
||||
name: 'id',
|
||||
value: props.rowKey,
|
||||
});
|
||||
}
|
||||
sorts.push({ name: 'createTime', order: 'desc' });
|
||||
p.sorts = sorts
|
||||
const resp = await queryProductList(p)
|
||||
if (resp.success && props.rowKey && firstFind.value) {
|
||||
const productItem = (resp.result as { data: any[]}).data.find((item: any) => item.id === props.rowKey)
|
||||
emit('update:detail', productItem)
|
||||
firstFind.value = false
|
||||
}
|
||||
return {
|
||||
...resp
|
||||
}
|
||||
}
|
||||
|
||||
const handleClick = (detail: any) => {
|
||||
emit('update:rowKey', detail.id)
|
||||
emit('change', detail)
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang='less'>
|
||||
.search {
|
||||
margin-bottom: 0;
|
||||
padding-right: 0px;
|
||||
padding-left: 0px;
|
||||
}
|
||||
</style>
|
|
@ -90,7 +90,7 @@
|
|||
<j-form ref="formRef" :model="formData.data" layout="vertical">
|
||||
<j-form-item
|
||||
:name="item.property"
|
||||
v-for="item in metadata.properties"
|
||||
v-for="item in metadata?.properties || []"
|
||||
:key="item"
|
||||
:label="item.name"
|
||||
:rules="[
|
||||
|
|
|
@ -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'"
|
||||
:provider="provider"
|
||||
:data="data"
|
||||
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,13 +134,7 @@ 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.push(item);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -0,0 +1,426 @@
|
|||
<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';
|
||||
import { CreteRuleByType } from 'components/Form/rules'
|
||||
|
||||
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,
|
||||
sorts: [{ name: 'createTime', order: 'desc' }],
|
||||
paging: false
|
||||
}).then(res => {
|
||||
pluginList.value = []
|
||||
if (res.success) {
|
||||
pluginList.value = res.result || []
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const getRules = (item: any) => {
|
||||
let typeName = '输入'
|
||||
let rules: any[] = []
|
||||
|
||||
if (['select', 'date'].includes(item.type?.type || 'string')) {
|
||||
typeName = '选择'
|
||||
}
|
||||
|
||||
if (item.required) {
|
||||
rules.push(
|
||||
{
|
||||
required: true,
|
||||
message: `请${typeName}${item.name}`
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
const typeRules = CreteRuleByType(item.type?.type)
|
||||
rules = [...rules, ...typeRules]
|
||||
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>
|
|
@ -98,7 +98,7 @@ const click = (value: object) => {
|
|||
width: 15%;
|
||||
min-width: 64px;
|
||||
height: 2px;
|
||||
background-image: url('/public/images/access/rectangle.png');
|
||||
background-image: url('/images/access/rectangle.png');
|
||||
background-repeat: no-repeat;
|
||||
background-size: 100% 100%;
|
||||
content: ' ';
|
||||
|
|
|
@ -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'));
|
||||
|
|
|
@ -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]"
|
||||
|
|
|
@ -0,0 +1,171 @@
|
|||
<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' />
|
||||
</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'
|
||||
|
||||
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>
|
|
@ -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='loading'
|
||||
:maxCount='1'
|
||||
>
|
||||
<div>
|
||||
<j-button>上传文件</j-button>
|
||||
<span class='upload-tip'>格式要求:{文件名}.jar/{文件名}.zip</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', 'zip'].includes(arr[arr.length - 1]); // file.type === 'application/zip' || file.type === 'application/javj-archive'
|
||||
if (!isFile) {
|
||||
onlyMessage('请上传.jar,.zip格式的文件', '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>
|
|
@ -0,0 +1,274 @@
|
|||
<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)'
|
||||
:statusNames='{
|
||||
processing: "processing"
|
||||
}'
|
||||
status='processing'
|
||||
>
|
||||
|
||||
<template #img>
|
||||
<img
|
||||
:width="80"
|
||||
:height="80"
|
||||
:src="getImage('/plug.png')"
|
||||
/>
|
||||
</template>
|
||||
<template #content>
|
||||
<div>
|
||||
<div>
|
||||
<j-tag class='plugin-version'>{{ slotProps.version }}</j-tag>
|
||||
</div>
|
||||
<Ellipsis style="width: calc(100% - 100px); margin-bottom: 18px;">
|
||||
<span style="font-size: 16px; font-weight: 600">
|
||||
{{ slotProps.name }}
|
||||
</span>
|
||||
</Ellipsis>
|
||||
</div>
|
||||
<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 lang='less'>
|
||||
.plugin-version {
|
||||
border-radius: 4px;
|
||||
}
|
||||
</style>
|
|
@ -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
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
export const TypeMap = {
|
||||
'deviceGateway': '设备接入网关',
|
||||
'thingsManager': '物管理',
|
||||
}
|
|
@ -185,7 +185,7 @@
|
|||
|
||||
<script lang="ts" setup>
|
||||
import InputSave from './Save/input.vue';
|
||||
import OutputSave from './save/output.vue';
|
||||
import OutputSave from './Save/output.vue';
|
||||
import { getDataExchange } from '@/api/rule-engine/config';
|
||||
import { getImage } from '@/utils/comm';
|
||||
import { marked } from 'marked';
|
||||
|
|
|
@ -101,7 +101,7 @@ import { useRoute } from 'vue-router';
|
|||
import type { ActionsType } from '@/components/Table';
|
||||
import { getImage } from '@/utils/comm';
|
||||
import { message } from 'jetlinks-ui-components';
|
||||
import Save from './save/index.vue';
|
||||
import Save from './Save/index.vue';
|
||||
import { useAlarmConfigurationStore } from '@/store/alarm';
|
||||
import { storeToRefs } from 'pinia';
|
||||
const route = useRoute();
|
||||
|
|
|
@ -374,10 +374,10 @@ const form = reactive<formType>({
|
|||
form.formValue = {
|
||||
title: configInfo.front?.title,
|
||||
headerTheme: configInfo.front?.headerTheme,
|
||||
logo: configInfo.front?.logo || '/public/logo.png',
|
||||
ico: configInfo.front?.ico || '/public/favicon.ico',
|
||||
logo: configInfo.front?.logo || '/logo.png',
|
||||
ico: configInfo.front?.ico || '/favicon.ico',
|
||||
backgroud:
|
||||
configInfo.front?.backgroud || '/public/images/login.png',
|
||||
configInfo.front?.backgroud || '/images/login.png',
|
||||
apiKey: configInfo.amap?.apiKey,
|
||||
'base-path': configInfo.paths?.['base-path'],
|
||||
};
|
||||
|
|
|
@ -92,9 +92,9 @@ export default defineConfig(({ mode}) => {
|
|||
|
||||
proxy: {
|
||||
[env.VITE_APP_BASE_API]: {
|
||||
target: 'http://192.168.32.226:8844',
|
||||
// target: 'http://192.168.32.226:8844',
|
||||
// target: 'http://192.168.32.244:8881',
|
||||
// target: 'http://120.77.179.54:8844', // 120测试
|
||||
target: 'http://120.77.179.54:8844', // 120测试
|
||||
// target: 'http://192.168.33.46:8844', // 本地开发环境
|
||||
ws: 'ws://192.168.33.46:8844',
|
||||
changeOrigin: true,
|
||||
|
|
150
yarn.lock
150
yarn.lock
|
@ -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"
|
||||
|
@ -3720,13 +3825,27 @@ jetlinks-store@^0.0.3:
|
|||
|
||||
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"
|
||||
|
||||
jetlinks-ui-components@^1.0.8:
|
||||
version "1.0.8"
|
||||
resolved "https://registry.jetlinks.cn/jetlinks-ui-components/-/jetlinks-ui-components-1.0.8.tgz#bcbdbbdc6c0011207f15cbb51fadcc8389803f53"
|
||||
integrity sha512-FdXSS4Wdnq5cCUKP5f6Z/3FHu3XHFkRIzSAvkUQdneHbYO6iHkEjMJyHChttlP9cp4s6ydRpeqY2jjtoftYhtA==
|
||||
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 +4728,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 +7035,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==
|
||||
|
|
Loading…
Reference in New Issue