fix: 运维管理 设备接入网关修复部分bug

This commit is contained in:
jackhoo_98 2023-03-16 15:59:01 +08:00
parent 62592b6e83
commit 05045768d2
10 changed files with 599 additions and 580 deletions

View File

@ -1,206 +1,225 @@
<template>
<j-spin :spinning="spinning">
<pro-search :columns="columns" target="search" @search="handleSearch" />
<j-pro-table
ref="tableRef"
model="CARD"
:columns="columns"
:gridColumn="2"
:gridColumns="[1, 2]"
:request="queryPoint"
:defaultParams="defaultParams"
:params="params"
:rowSelection="{
selectedRowKeys: _selectedRowKeys,
onChange: onSelectChange,
}"
@cancelSelect="cancelSelect"
>
<template #headerTitle>
<j-space>
<PermissionButton
v-if="data?.provider !== 'OPC_UA'"
type="primary"
@click="handlAdd"
hasPermission="DataCollect/Collector:add"
>
<template #icon><AIcon type="PlusOutlined" /></template>
新增点位
</PermissionButton>
<j-scrollbar height="680">
<j-pro-table
ref="tableRef"
model="CARD"
:columns="columns"
:gridColumn="2"
:gridColumns="[1, 2]"
:request="queryPoint"
:defaultParams="defaultParams"
:params="params"
:rowSelection="{
selectedRowKeys: _selectedRowKeys,
onChange: onSelectChange,
}"
@cancelSelect="cancelSelect"
>
<template #headerTitle>
<j-space>
<PermissionButton
v-if="data?.provider !== 'OPC_UA'"
type="primary"
@click="handlAdd"
hasPermission="DataCollect/Collector:add"
>
<template #icon
><AIcon type="PlusOutlined"
/></template>
新增点位
</PermissionButton>
<PermissionButton
<PermissionButton
v-if="data?.provider === 'OPC_UA'"
type="primary"
@click="handlScan"
hasPermission="DataCollect/Collector:add"
>
<template #icon
><AIcon type="PlusOutlined"
/></template>
扫描
</PermissionButton>
<j-dropdown v-if="data?.provider === 'OPC_UA'">
<j-button
>批量操作 <AIcon type="DownOutlined"
/></j-button>
<template #overlay>
<j-menu>
<j-menu-item>
<PermissionButton
hasPermission="DataCollect/Collector:update"
@click="handlBatchUpdate()"
>
<template #icon
><AIcon type="FormOutlined"
/></template>
编辑
</PermissionButton>
</j-menu-item>
<j-menu-item>
<PermissionButton
hasPermission="DataCollect/Collector:delete"
:popConfirm="{
title: `确定删除?`,
onConfirm: () => handlDelete(),
}"
>
<template #icon
><AIcon type="EditOutlined"
/></template>
删除
</PermissionButton>
</j-menu-item>
</j-menu>
</template>
</j-dropdown>
</j-space>
<div
v-if="data?.provider === 'OPC_UA'"
type="primary"
@click="handlScan"
hasPermission="DataCollect/Collector:add"
style="margin-top: 15px"
>
<template #icon><AIcon type="PlusOutlined" /></template>
扫描
</PermissionButton>
<j-dropdown v-if="data?.provider === 'OPC_UA'">
<j-button
>批量操作 <AIcon type="DownOutlined"
/></j-button>
<template #overlay>
<j-menu>
<j-menu-item>
<PermissionButton
hasPermission="DataCollect/Collector:update"
@click="handlBatchUpdate()"
>
<template #icon
><AIcon type="FormOutlined"
/></template>
编辑
</PermissionButton>
</j-menu-item>
<j-menu-item>
<PermissionButton
hasPermission="DataCollect/Collector:delete"
:popConfirm="{
title: `确定删除?`,
onConfirm: () => handlDelete(),
}"
>
<template #icon
><AIcon type="EditOutlined"
/></template>
删除
</PermissionButton>
</j-menu-item>
</j-menu>
<j-checkbox
v-model:checked="checkAll"
@change="onCheckAllChange"
>全选</j-checkbox
>
</div>
</template>
<template #card="slotProps">
<PointCardBox
:showStatus="true"
:value="slotProps"
@click="handleClick"
:active="_selectedRowKeys.includes(slotProps.id)"
class="card-box"
:status="getState(slotProps).value"
:statusText="getState(slotProps)?.text"
:statusNames="Object.fromEntries(colorMap.entries())"
>
<template #title>
<slot name="title">
<div class="card-box-title">
{{ slotProps.name }}
</div>
</slot>
</template>
</j-dropdown>
</j-space>
<div
v-if="data?.provider === 'OPC_UA'"
style="margin-top: 15px"
>
<j-checkbox
v-model:checked="checkAll"
@change="onCheckAllChange"
>全选</j-checkbox
>
</div>
</template>
<template #card="slotProps">
<PointCardBox
:showStatus="true"
:value="slotProps"
@click="handleClick"
:active="_selectedRowKeys.includes(slotProps.id)"
class="card-box"
:status="getState(slotProps).value"
:statusText="getState(slotProps)?.text"
:statusNames="Object.fromEntries(colorMap.entries())"
>
<template #title>
<slot name="title">
<div class="card-box-title">
{{ slotProps.name }}
<template #action>
<div class="card-box-action">
<j-popconfirm
title="确定删除?"
@confirm="handlDelete(slotProps.id)"
>
<a><AIcon type="DeleteOutlined" /></a>
</j-popconfirm>
<a @click="handlEdit(slotProps)"
><AIcon type="FormOutlined"
/></a>
</div>
</slot>
</template>
<template #action>
<div class="card-box-action">
<j-popconfirm
title="确定删除?"
@confirm="handlDelete(slotProps.id)"
>
<a><AIcon type="DeleteOutlined" /></a>
</j-popconfirm>
<a @click="handlEdit(slotProps)"
><AIcon type="FormOutlined"
/></a>
</div>
</template>
<template #img>
<img
:src="
slotProps.provider === 'OPC_UA'
? opcImage
: modbusImage
"
/>
</template>
<template #content>
<div class="card-box-content">
<div class="card-box-content-left">
<div class="card-box-content-left-1">
</template>
<template #img>
<img
:src="
slotProps.provider === 'OPC_UA'
? opcImage
: modbusImage
"
/>
</template>
<template #content>
<div class="card-box-content">
<div class="card-box-content-left">
<div class="card-box-content-left-1">
<div
class="ard-box-content-left-1-title"
v-if="
propertyValue.has(slotProps.id)
"
>
<j-ellipsis
style="max-width: 150px"
>
{{
propertyValue.get(
slotProps.id,
)?.parseData[0] || 0
}}({{
propertyValue.get(
slotProps.id,
)?.dataType
}})
</j-ellipsis>
</div>
<span v-else>--</span>
<a
v-if="
getAccessModes(
slotProps,
).includes('write')
"
@click.stop="clickEdit(slotProps)"
><AIcon type="EditOutlined"
/></a>
<a
v-if="
getAccessModes(
slotProps,
).includes('read')
"
@click.stop="clickRedo(slotProps)"
><AIcon type="RedoOutlined"
/></a>
</div>
<div
class="ard-box-content-left-1-title"
v-if="propertyValue.has(slotProps.id)"
class="card-box-content-right-2"
>
<j-ellipsis style="max-width: 150px">
<p>
{{
propertyValue.get(slotProps.id)
?.parseData[0] || 0
}}({{
propertyValue.get(slotProps.id)
?.dataType
}})
</j-ellipsis>
?.hex || ''
}}
</p>
<p>
{{
moment(
propertyValue.get(
slotProps.id,
)?.timestamp,
).format('YYYY-MM-DD HH:mm:ss')
}}
</p>
</div>
<span v-else>--</span>
<a
v-if="
getAccessModes(slotProps).includes(
'write',
)
"
@click.stop="clickEdit(slotProps)"
><AIcon type="EditOutlined"
/></a>
<a
v-if="
getAccessModes(slotProps).includes(
'read',
)
"
@click.stop="clickRedo(slotProps)"
><AIcon type="RedoOutlined"
/></a>
</div>
<div
v-if="propertyValue.has(slotProps.id)"
class="card-box-content-right-2"
>
<p>
{{
propertyValue.get(slotProps.id)
?.hex || ''
}}
</p>
<p>
{{
moment(
propertyValue.get(slotProps.id)
?.timestamp,
).format('YYYY-MM-DD HH:mm:ss')
}}
</p>
</div>
</div>
<div class="card-box-content-right">
<div
v-if="getRight1(slotProps)"
class="card-box-content-right-1"
>
<span>{{ getQuantity(slotProps) }}</span>
<span>{{ getAddress(slotProps) }}</span>
<span>{{ getScaleFactor(slotProps) }}</span>
</div>
<div class="card-box-content-right-2">
<span>{{ getText(slotProps) }}</span>
<span>{{ getInterval(slotProps) }}</span>
<div class="card-box-content-right">
<div
v-if="getRight1(slotProps)"
class="card-box-content-right-1"
>
<span>{{
getQuantity(slotProps)
}}</span>
<span>{{ getAddress(slotProps) }}</span>
<span>{{
getScaleFactor(slotProps)
}}</span>
</div>
<div class="card-box-content-right-2">
<span>{{ getText(slotProps) }}</span>
<span>{{
getInterval(slotProps)
}}</span>
</div>
</div>
</div>
</div>
</template>
</PointCardBox>
</template>
</j-pro-table>
</template>
</PointCardBox>
</template>
</j-pro-table>
</j-scrollbar>
<SaveModBus
v-if="visible.saveModBus"
:data="current"

View File

@ -48,7 +48,7 @@ const checkedChange = (id: string) => {
overflow: hidden;
background: url('/public/images/access.png') no-repeat;
background-size: 100% 100%;
min-height: 105px;
height: 120px;
.title {
width: calc(100% - 88px);
@ -94,7 +94,6 @@ const checkedChange = (id: string) => {
position: relative;
color: #2f54eb;
border-color: #2f54eb;
.checked-icon {
display: block;
}

View File

@ -108,50 +108,52 @@
</j-row> </j-form
></j-col>
<j-col :span="8">
<div class="doc">
<h1>操作指引</h1>
<div>
1CTWing端创建产品设备以及一个第三方应用
</div>
<div>
2CTWing端配置产品/设备/分组级订阅订阅方URL地址请填写:
<div style="word-wrap: break-word">
{{
`${origin}/api/ctwing/${randomString()}/notify`
}}
<j-scrollbar height="500">
<div class="doc">
<h1>操作指引</h1>
<div>
1CTWing端创建产品设备以及一个第三方应用
</div>
<div>
2CTWing端配置产品/设备/分组级订阅订阅方URL地址请填写:
<div style="word-wrap: break-word">
{{
`${origin}/api/ctwing/${randomString()}/notify`
}}
</div>
</div>
<div class="image">
<j-image width="100%" :src="img1" />
</div>
<div>
3IOT端创建类型为CTWing的设备接入网关
</div>
<div>
4IOT端创建产品选中接入方式为CTWing,填写CTWing平台中的产品IDMaster-APIkey
</div>
<div class="image">
<j-image width="100%" :src="img2" />
</div>
<div>
5IOT端添加设备为每一台设备设置唯一的IMEI需与CTWing平台中填写的值一致
</div>
<div class="image">
<j-image width="100%" :src="img3" />
</div>
<h1>设备接入网关配置说明</h1>
<div>
1.请将CTWing的AEP平台-应用管理中的App
Key和App Secret复制到当前页面
</div>
<div class="image">
<j-image width="100%" :src="img4" />
</div>
<h1>其他说明</h1>
<div>
1.在IOT端启用设备时若CTWing平台没有与之对应的设备则将在CTWing端自动创建新设备
</div>
</div>
<div class="image">
<j-image width="100%" :src="img1" />
</div>
<div>
3IOT端创建类型为CTWing的设备接入网关
</div>
<div>
4IOT端创建产品选中接入方式为CTWing,填写CTWing平台中的产品IDMaster-APIkey
</div>
<div class="image">
<j-image width="100%" :src="img2" />
</div>
<div>
5IOT端添加设备为每一台设备设置唯一的IMEI需与CTWing平台中填写的值一致
</div>
<div class="image">
<j-image width="100%" :src="img3" />
</div>
<h1>设备接入网关配置说明</h1>
<div>
1.请将CTWing的AEP平台-应用管理中的App
Key和App Secret复制到当前页面
</div>
<div class="image">
<j-image width="100%" :src="img4" />
</div>
<h1>其他说明</h1>
<div>
1.在IOT端启用设备时若CTWing平台没有与之对应的设备则将在CTWing端自动创建新设备
</div>
</div>
</j-scrollbar>
</j-col>
</j-row>
</div>
@ -179,8 +181,12 @@
新增
</PermissionButton>
</div>
<div class="card-item">
<j-row :gutter="[24, 24]" v-if="procotolList.length > 0">
<j-scrollbar height="500">
<j-row
:gutter="[24, 24]"
v-if="procotolList.length > 0"
style="margin-right: 10px"
>
<j-col
:span="8"
v-for="item in procotolList"
@ -195,7 +201,7 @@
</j-col>
</j-row>
<j-empty v-else description="暂无数据" />
</div>
</j-scrollbar>
</div>
</div>
<div v-if="current === 2" class="card-last">
@ -362,26 +368,24 @@ const formData = ref<Form>({
const current = ref(0);
const stepCurrent = ref(0);
const steps = ref(['接入配置', '消息协议', '完成']);
const procotolList = ref([]);
const procotolList: any = ref([]);
const allProcotolList = ref([]);
const procotolCurrent = ref('');
const procotolCurrent: any = ref('');
const procotolChange = (id: string) => {
procotolCurrent.value = id;
};
const procotolSearch = (value: string) => {
if (value) {
const list = allProcotolList.value.filter((i) => {
return (
i.name &&
i.name.toLocaleLowerCase().includes(value.toLocaleLowerCase())
);
});
procotolList.value = list;
} else {
procotolList.value = allProcotolList.value;
}
procotolList.value = value
? allProcotolList.value.filter(
(i: any) =>
i.name &&
i.name
.toLocaleLowerCase()
.includes(value.toLocaleLowerCase()),
)
: allProcotolList.value;
};
const saveData = async () => {
@ -411,7 +415,7 @@ const saveData = async () => {
};
const queryProcotolList = async (id: string, params = {}) => {
const resp = await getProtocolList(ProtocolMapping.get(id), {
const resp: any = await getProtocolList(ProtocolMapping.get(id), {
...params,
'sorts[0].name': 'createTime',
'sorts[0].order': 'desc',
@ -424,10 +428,10 @@ const queryProcotolList = async (id: string, params = {}) => {
const addProcotol = () => {
const url = menuStory.menus['link/Protocol']?.path;
const tab = window.open(
const tab: any = window.open(
`${window.location.origin + window.location.pathname}#${url}?save=true`,
);
tab.onTabSaveSuccess = (value) => {
tab.onTabSaveSuccess = (value: any) => {
if (value.success) {
procotolCurrent.value = value.result?.id;
queryProcotolList(props.provider?.id);
@ -486,12 +490,7 @@ watch(
}
.steps-box {
min-height: 400px;
.card-item {
padding-right: 5px;
max-height: 480px;
overflow-y: auto;
overflow-x: hidden;
}
.card-last {
padding-right: 5px;
overflow-y: auto;

View File

@ -29,23 +29,17 @@
},
]"
>
<div class="form-label">
<template #label>
接口地址
<span
class="form-label-required"
>*</span
<j-tooltip
title="同步物联网平台设备数据到OneNet"
>
<j-tooltip>
<template #title>
<p>
同步物联网平台设备数据到OneNet
</p>
</template>
<AIcon
type="QuestionCircleOutlined"
style="margin-left: 2px"
/>
</j-tooltip>
</div>
</template>
<j-input
disabled
v-model:value="
@ -95,23 +89,17 @@
},
]"
>
<div class="form-label">
<template #label>
通知Token
<span
class="form-label-required"
>*</span
<j-tooltip
title="接收OneNet推送的Token地址"
>
<j-tooltip>
<template #title>
<p>
接收OneNet推送的Token地址
</p>
</template>
<AIcon
type="QuestionCircleOutlined"
style="margin-left: 2px"
/>
</j-tooltip>
</div>
</template>
<j-input
v-model:value="
formState.validateToken
@ -131,20 +119,17 @@
},
]"
>
<div class="form-label">
<template #label>
aesKey
<j-tooltip>
<template #title>
<p>
OneNet
端生成的消息加密key
</p>
</template>
<j-tooltip
title="OneNet端生成的消息加密key"
>
<AIcon
type="QuestionCircleOutlined"
style="margin-left: 2px"
/>
</j-tooltip>
</div>
</template>
<j-input
v-model:value="formState.aesKey"
placeholder="请输入aesKey"
@ -171,86 +156,88 @@
</j-row> </j-form
></j-col>
<j-col :span="8">
<div class="doc">
<h1>操作指引</h1>
<div>
1OneNet端创建产品设备并配置HTTP推送
</div>
<div>
2IOT端创建类型为OneNet的设备接入网关
</div>
<div>
3IOT端创建产品选中接入方式为OneNet类型的设备接入网关填写Master-APIkeyOneNet端的产品Key
</div>
<div class="image">
<j-image width="100%" :src="img5" />
</div>
<div>
4IOT端添加设备在设备实例页面为每一台设备设置唯一的IMEIIMSI码需与OneNet平台中的值一致
</div>
<div class="image">
<j-image width="100%" :src="img6" />
</div>
<h1>HTTP推送配置说明</h1>
<div class="image">
<j-image width="100%" :src="img" />
</div>
<div>
HTTP推送配置路径应用开发&gt;数据推送
</div>
<j-descriptions
bordered
size="small"
:column="1"
:labelStyle="{ width: '100px' }"
>
<j-descriptions-item label="参数"
>说明</j-descriptions-item
<j-scrollbar height="500">
<div class="doc">
<h1>操作指引</h1>
<div>
1OneNet端创建产品设备并配置HTTP推送
</div>
<div>
2IOT端创建类型为OneNet的设备接入网关
</div>
<div>
3IOT端创建产品选中接入方式为OneNet类型的设备接入网关填写Master-APIkeyOneNet端的产品Key
</div>
<div class="image">
<j-image width="100%" :src="img5" />
</div>
<div>
4IOT端添加设备在设备实例页面为每一台设备设置唯一的IMEIIMSI码需与OneNet平台中的值一致
</div>
<div class="image">
<j-image width="100%" :src="img6" />
</div>
<h1>HTTP推送配置说明</h1>
<div class="image">
<j-image width="100%" :src="img" />
</div>
<div>
HTTP推送配置路径应用开发&gt;数据推送
</div>
<j-descriptions
bordered
size="small"
:column="1"
:labelStyle="{ width: '100px' }"
>
<j-descriptions-item label="实例名称"
>推送实例的名称</j-descriptions-item
>
<j-descriptions-item label="推送地址">
用于接收OneNet推送设备数据的地址物联网平台地址:
<div style="word-wrap: break-word">
{{
`${origin}/api/one-net/${randomString()}/notify`
}}
</div>
</j-descriptions-item>
<j-descriptions-item label="Token">
自定义token,可用于验证请求是否来自OneNet
</j-descriptions-item>
<j-descriptions-item label="消息加密">
采用AES加密算法对推送的数据进行数据加密AesKey为加密秘钥
</j-descriptions-item>
</j-descriptions>
<j-descriptions-item label="参数"
>说明</j-descriptions-item
>
<j-descriptions-item label="实例名称"
>推送实例的名称</j-descriptions-item
>
<j-descriptions-item label="推送地址">
用于接收OneNet推送设备数据的地址物联网平台地址:
<div style="word-wrap: break-word">
{{
`${origin}/api/one-net/${randomString()}/notify`
}}
</div>
</j-descriptions-item>
<j-descriptions-item label="Token">
自定义token,可用于验证请求是否来自OneNet
</j-descriptions-item>
<j-descriptions-item label="消息加密">
采用AES加密算法对推送的数据进行数据加密AesKey为加密秘钥
</j-descriptions-item>
</j-descriptions>
<h1>设备接入网关配置说明</h1>
<j-descriptions
bordered
size="small"
:column="1"
:labelStyle="{ width: '100px' }"
>
<j-descriptions-item label="参数"
>说明</j-descriptions-item
<h1>设备接入网关配置说明</h1>
<j-descriptions
bordered
size="small"
:column="1"
:labelStyle="{ width: '100px' }"
>
<j-descriptions-item label="apiKey"
>OneNet平台中具体产品的Key</j-descriptions-item
>
<j-descriptions-item label="通知Token">
填写OneNet数据推送配置中设置的Token
</j-descriptions-item>
<j-descriptions-item label="aesKey">
若OneNet数据推送配置了消息加密此处填写OneNet端数据推送配置中设置的aesKey
</j-descriptions-item>
</j-descriptions>
<h1>其他说明</h1>
<div>
1.在IOT端启用设备时若OneNet平台没有与之对应的设备则将在OneNet端自动创建新设备
<j-descriptions-item label="参数"
>说明</j-descriptions-item
>
<j-descriptions-item label="apiKey"
>OneNet平台中具体产品的Key</j-descriptions-item
>
<j-descriptions-item label="通知Token">
填写OneNet数据推送配置中设置的Token
</j-descriptions-item>
<j-descriptions-item label="aesKey">
若OneNet数据推送配置了消息加密此处填写OneNet端数据推送配置中设置的aesKey
</j-descriptions-item>
</j-descriptions>
<h1>其他说明</h1>
<div>
1.在IOT端启用设备时若OneNet平台没有与之对应的设备则将在OneNet端自动创建新设备
</div>
</div>
</div>
</j-scrollbar>
</j-col>
</j-row>
</div>
@ -278,8 +265,12 @@
新增
</PermissionButton>
</div>
<div class="card-item">
<j-row :gutter="[24, 24]" v-if="procotolList.length > 0">
<j-scrollbar height="500">
<j-row
:gutter="[24, 24]"
v-if="procotolList.length > 0"
style="margin-right: 10px"
>
<j-col
:span="8"
v-for="item in procotolList"
@ -294,7 +285,7 @@
</j-col>
</j-row>
<j-empty v-else description="暂无数据" />
</div>
</j-scrollbar>
</div>
</div>
<div v-if="current === 2" class="card-last">
@ -463,26 +454,24 @@ const formData = ref<Form>({
const current = ref(0);
const stepCurrent = ref(0);
const steps = ref(['接入配置', '消息协议', '完成']);
const procotolList = ref([]);
const procotolList: any = ref([]);
const allProcotolList = ref([]);
const procotolCurrent = ref('');
const procotolCurrent: any = ref('');
const procotolChange = (id: string) => {
procotolCurrent.value = id;
};
const procotolSearch = (value: string) => {
if (value) {
const list = allProcotolList.value.filter((i) => {
return (
i.name &&
i.name.toLocaleLowerCase().includes(value.toLocaleLowerCase())
);
});
procotolList.value = list;
} else {
procotolList.value = allProcotolList.value;
}
procotolList.value = value
? allProcotolList.value.filter(
(i: any) =>
i.name &&
i.name
.toLocaleLowerCase()
.includes(value.toLocaleLowerCase()),
)
: allProcotolList.value;
};
const saveData = async () => {
@ -513,7 +502,7 @@ const saveData = async () => {
};
const queryProcotolList = async (id: string, params = {}) => {
const resp = await getProtocolList(ProtocolMapping.get(id), {
const resp: any = await getProtocolList(ProtocolMapping.get(id), {
...params,
'sorts[0].name': 'createTime',
'sorts[0].order': 'desc',
@ -526,10 +515,10 @@ const queryProcotolList = async (id: string, params = {}) => {
const addProcotol = () => {
const url = menuStory.menus['link/Protocol']?.path;
const tab = window.open(
const tab: any = window.open(
`${window.location.origin + window.location.pathname}#${url}?save=true`,
);
tab.onTabSaveSuccess = (value) => {
tab.onTabSaveSuccess = (value: any) => {
if (value.success) {
procotolCurrent.value = value.result?.id;
queryProcotolList(props.provider?.id);
@ -587,12 +576,6 @@ watch(
}
.steps-box {
min-height: 400px;
.card-item {
padding-right: 5px;
max-height: 480px;
overflow-y: auto;
overflow-x: hidden;
}
.card-last {
padding-right: 5px;
overflow-y: auto;

View File

@ -29,14 +29,18 @@
新增
</PermissionButton>
</div>
<div class="card-item">
<j-row :gutter="[24, 24]" v-if="networkList.length > 0">
<j-scrollbar height="500">
<j-row
:gutter="[24, 24]"
v-if="networkList.length > 0"
style="margin-right: 10px"
>
<j-col
:span="8"
v-for="item in networkList"
:key="item.id"
>
<access-card
<AccessCard
@checkedChange="checkedChange"
:checked="networkCurrent"
:data="{
@ -96,11 +100,11 @@
</j-tooltip>
</div>
</template>
</access-card>
</AccessCard>
</j-col>
</j-row>
<j-empty v-else description="暂无数据" />
</div>
</j-scrollbar>
</div>
</div>
<div
@ -250,9 +254,9 @@ const formRef = ref<FormInstance>();
const current = ref(0);
const stepCurrent = ref(0);
const steps = ref(['网络组件', '完成']);
const networkCurrent = ref('');
const networkList = ref([]);
const allNetworkList = ref([]);
const networkCurrent: any = ref('');
const networkList: any = ref([]);
const allNetworkList: any = ref([]);
const onFinish = async (values: any) => {
const providerId = props.provider.id;
@ -288,15 +292,15 @@ const queryNetworkList = async (id: string, include: string, data = {}) => {
};
const networkSearch = (value: string) => {
if (value) {
networkList.value = allNetworkList.value.filter(
(i: any) =>
i.name &&
i.name.toLocaleLowerCase().includes(value.toLocaleLowerCase()),
);
} else {
networkList.value = allNetworkList.value;
}
networkList.value = value
? allNetworkList.value.filter(
(i: any) =>
i.name &&
i.name
.toLocaleLowerCase()
.includes(value.toLocaleLowerCase()),
)
: allNetworkList.value;
};
const saveData = async () => {
@ -306,12 +310,12 @@ const saveData = async () => {
const addNetwork = () => {
const url = menuStory.menus['link/Type/Detail']?.path;
const tab = window.open(
const tab: any = window.open(
`${window.location.origin + window.location.pathname}#${url}?type=${
NetworkTypeMapping.get(props.provider?.id) || ''
}`,
);
tab.onTabSaveSuccess = (value) => {
tab.onTabSaveSuccess = (value: any) => {
if (value.success) {
networkCurrent.value = value.result.id;
queryNetworkList(props.provider?.id, networkCurrent.value || '');
@ -364,12 +368,6 @@ watch(
}
.steps-box {
min-height: 400px;
.card-item {
padding-right: 5px;
max-height: 480px;
overflow-y: auto;
overflow-x: hidden;
}
.card-last {
padding-right: 5px;
overflow-y: auto;
@ -405,9 +403,6 @@ watch(
}
.config-right {
padding: 20px;
// color: rgba(0, 0, 0, 0.8);
// background: rgba(0, 0, 0, 0.04);
.config-right-item {
margin-bottom: 10px;

View File

@ -71,24 +71,17 @@
},
]"
>
<div>
<template #label>
集群
<span style="color: red; margin: 0 4px 0 -2px"
>*</span
<j-tooltip
title="共享配置:集群下所有节点共用同一配置,独立配置:集群下不同节点使用不同配置"
>
<j-tooltip>
<template #title>
<p>
共享配置:集群下所有节点共用同一配置
</p>
<p>
独立配置:集群下不同节点使用不同配置
</p>
</template>
<AIcon type="QuestionCircleOutlined" />
<AIcon
type="QuestionCircleOutlined"
style="margin-left: 2px"
/>
</j-tooltip>
</div>
</template>
<j-radio-group
v-model:value="formState.shareCluster"
>
@ -218,20 +211,26 @@
:header="`#${index + 1}.节点`"
>
<template #extra>
<AIcon type="DeleteOutlined" />
<AIcon
@click="removeCluster(cluster)"
type="DeleteOutlined"
/>
</template>
<j-row :gutter="[24, 24]">
<j-col :span="8">
<j-form-item
label="节点名称"
:name="[
'cluster',
index,
'clusterNodeId',
]"
:rules="{
required: true,
message:
'请选择节点名称',
}"
>
<div class="form-label">
节点名称
</div>
<j-select
v-model:value="
cluster.clusterNodeId
@ -527,22 +526,22 @@ import { getResourcesCurrent, getClusters } from '@/api/link/accessConfig';
import { update, save } from '@/api/link/accessConfig';
interface Form2 {
clusterNodeId: string;
port: string;
host: string;
publicPort: string;
publicHost: string;
clusterNodeId: string | undefined;
port: string | undefined;
host: string | undefined;
publicPort: string | undefined;
publicHost: string | undefined;
id: number;
}
interface FormState {
domain: string;
sipId: string;
domain: string | undefined;
sipId: string | undefined;
shareCluster: boolean;
hostPort: {
port: string;
host: string;
publicPort: string;
publicHost: string;
port: string | undefined;
host: string | undefined;
publicPort: string | undefined;
publicHost: string | undefined;
};
}
@ -576,14 +575,14 @@ const formData = ref({
description: '',
});
let formState = ref<FormState>({
domain: '',
sipId: '',
domain: undefined,
sipId: undefined,
shareCluster: true,
hostPort: {
port: '',
port: undefined,
host: '0.0.0.0',
publicPort: '',
publicHost: '',
publicPort: undefined,
publicHost: undefined,
},
});
@ -610,11 +609,11 @@ const removeCluster = (item: Form2) => {
const addCluster = () => {
const id = Date.now();
dynamicValidateForm.cluster.push({
clusterNodeId: '',
port: '',
host: '',
publicPort: '',
publicHost: '',
clusterNodeId: undefined,
port: undefined,
host: undefined,
publicPort: undefined,
publicHost: undefined,
id,
});
activeKey.value = [...activeKey.value, id.toString()];
@ -665,16 +664,7 @@ const saveData = () => {
id === ':id' ? await save(params) : await update({ ...params, id });
if (resp.status === 200) {
message.success('操作成功!');
// if (params.get('save')) {
// if ((window as any).onTabSaveSuccess) {
// if (resp.result) {
// (window as any).onTabSaveSuccess(resp.result);
// setTimeout(() => window.close(), 300);
// }
// }
// } else {
history.back();
// }
}
});
};
@ -709,14 +699,14 @@ onMounted(() => {
getResourcesCurrent().then((resp) => {
if (resp.status === 200) {
sipListConst = resp.result;
sipListOption.value = sipListConst.map((i) => ({
sipListOption.value = sipListConst.map((i: any) => ({
value: i.host,
label: i.host,
}));
sipList.value = sipListConst
.find((i) => i.host === '0.0.0.0')
?.portList.map((i) => {
.find((i: any) => i.host === '0.0.0.0')
?.portList.map((i: any) => {
return {
value: JSON.stringify({
host: '0.0.0.0',
@ -728,9 +718,9 @@ onMounted(() => {
}
});
getClusters().then((resp) => {
getClusters().then((resp: any) => {
if (resp.status === 200) {
const list = resp.result.map((i) => ({
const list = resp.result.map((i: any) => ({
value: i.id,
label: i.name,
}));

View File

@ -25,8 +25,12 @@
新增
</PermissionButton>
</div>
<div class="card-item">
<j-row :gutter="[24, 24]" v-if="networkList.length > 0">
<j-scrollbar height="480">
<j-row
:gutter="[24, 24]"
v-if="networkList.length > 0"
style="margin-right: 10px"
>
<j-col
:span="8"
v-for="item in networkList"
@ -88,7 +92,7 @@
</j-col>
</j-row>
<j-empty v-else description="暂无数据" />
</div>
</j-scrollbar>
</div>
<div class="steps-box" v-else-if="current === 1">
<div class="alert">
@ -111,8 +115,12 @@
新增
</PermissionButton>
</div>
<div class="card-item">
<j-row :gutter="[24, 24]" v-if="procotolList.length > 0">
<j-scrollbar height="480">
<j-row
:gutter="[24, 24]"
v-if="procotolList.length > 0"
style="margin-right: 10px"
>
<j-col
:span="8"
v-for="item in procotolList"
@ -127,7 +135,7 @@
</j-col>
</j-row>
<j-empty v-else description="暂无数据" />
</div>
</j-scrollbar>
</div>
<div class="steps-box" v-else>
<div
@ -169,97 +177,111 @@
</j-form>
</j-col>
<j-col :span="12">
<div class="config-right">
<div class="config-right-item">
<div class="config-right-item-title">
接入方式
<j-scrollbar height="600">
<div class="config-right">
<div class="config-right-item">
<div class="config-right-item-title">
接入方式
</div>
<div class="config-right-item-context">
{{ provider.name }}
</div>
<div class="config-right-item-context">
{{ provider.description }}
</div>
</div>
<div class="config-right-item-context">
{{ provider.name }}
</div>
<div class="config-right-item-context">
{{ provider.description }}
</div>
</div>
<div class="config-right-item">
<div class="config-right-item-title">
消息协议
</div>
<div class="config-right-item-context">
{{
procotolList.find(
(i) => i.id === procotolCurrent,
).name
}}
</div>
<div
class="config-right-item-context"
v-if="config.document"
>
<Markdown :source="config.document" />
</div>
</div>
<div
class="config-right-item"
v-if="getNetworkCurrent()"
>
<div class="config-right-item-title">
网络组件
</div>
<div
v-for="i in getNetworkCurrentData()"
:key="i.address"
>
<j-badge
:color="getColor(i)"
:text="i.address"
/>
</div>
</div>
<div
class="config-right-item"
v-if="
config.routes &&
config.routes.length > 0
"
>
<div class="config-right-item-title">
{{
data.provider ===
'mqtt-server-gateway' ||
data.provider ===
'mqtt-client-gateway'
? 'topic'
: 'URL信息'
}}
</div>
<j-table
:pagination="false"
:rowKey="generateUUID()"
:datj-source="config.routes || []"
bordered
:columns="
config.id === 'MQTT'
? columnsMQTT
: columnsHTTP
"
:scroll="{ y: 300 }"
>
<template
#bodyCell="{ column, text, record }"
<div class="config-right-item">
<div class="config-right-item-title">
消息协议
</div>
<div class="config-right-item-context">
{{
procotolList.find(
(i: any) =>
i.id ===
procotolCurrent,
).name
}}
</div>
<div
class="config-right-item-context"
v-if="config.document"
>
<template
v-if="
column.dataIndex ===
'stream'
<Markdown
:source="config.document"
/>
</div>
</div>
<div
class="config-right-item"
v-if="getNetworkCurrent()"
>
<div class="config-right-item-title">
网络组件
</div>
<div
v-for="i in getNetworkCurrentData()"
:key="i.address"
>
<j-badge
:color="getColor(i)"
:text="i.address"
/>
</div>
</div>
<div
class="config-right-item"
v-if="
config.routes &&
config.routes.length > 0
"
>
<div class="config-right-item-title">
{{
data.provider ===
'mqtt-server-gateway' ||
data.provider ===
'mqtt-client-gateway'
? 'topic'
: 'URL信息'
}}
</div>
<j-scrollbar height="200">
<j-table
:pagination="false"
:rowKey="generateUUID()"
:data-source="
config.routes || []
"
bordered
:columns="
config.id === 'MQTT'
? columnsMQTT
: columnsHTTP
"
:scroll="{ y: 300 }"
>
{{ getStream(record) }}
</template>
</template>
</j-table>
<template
#bodyCell="{
column,
text,
record,
}"
>
<template
v-if="
column.dataIndex ===
'stream'
"
>
{{ getStream(record) }}
</template>
</template>
</j-table>
</j-scrollbar>
</div>
</div>
</div>
</j-scrollbar>
</j-col>
</j-row>
</div>
@ -444,6 +466,8 @@ const getNetworkCurrentData = () =>
const getColor = (i: any) => (i.health === -1 ? 'red' : 'green');
const getStream = (record: any) => {
console.log(222, record);
let stream = '';
if (record.upstream && record.downstream) stream = '上行、下行';
else if (record.upstream) stream = '上行';
@ -493,19 +517,16 @@ const saveData = () => {
protocol: procotolCurrent.value,
channel: 'network', //
channelId: networkCurrent.value,
provider: props.provider.id,
transport:
props.provider?.id === 'child-device'
? 'Gateway'
: ProtocolMapping.get(props.provider.id),
};
const resp =
id === ':id'
? await save(params)
: await update({
...params,
id,
provider: props.provider.id,
transport:
props.provider?.id === 'child-device'
? 'Gateway'
: ProtocolMapping.get(props.provider.id),
});
: await update({ ...params, id });
if (resp.status === 200) {
message.success('操作成功!');
history.back();
@ -549,7 +570,6 @@ const next = async () => {
rowSpan: 0,
};
const list = config.value?.routes || [];
const arr = list.filter(
(res: any) => res.group === record.group,
);
@ -558,7 +578,6 @@ const next = async () => {
rowIndex === 0 ||
list[rowIndex - 1].group !== record.group;
isRowIndex && (obj.rowSpan = arr.length);
return obj;
},
};
@ -629,12 +648,6 @@ watch(
}
.steps-box {
min-height: 400px;
.card-item {
padding-right: 5px;
max-height: 480px;
overflow-y: auto;
overflow-x: hidden;
}
.card-last {
padding-right: 5px;
overflow-y: auto;

View File

@ -6,7 +6,6 @@
target="search"
@search="handleSearch"
/>
<j-pro-table
ref="tableRef"
model="CARD"
@ -353,6 +352,12 @@ const handleSearch = (e: any) => {
};
</script>
<style lang="less" scoped>
.table {
max-height: 700px;
overflow-y: auto;
overflow-x: hidden;
}
.tableCardDisabled {
width: 100%;
background: url('/images/access-config-diaabled.png') no-repeat;

View File

@ -135,11 +135,17 @@ const changeType = (value: Array<string>) => {
const onSubmit = async () => {
const data: any = await formRef.value?.validate();
loading.value = true;
const response = !id
const response: any = !id
? await save(data).catch(() => {})
: await update({ ...props.data, ...data }).catch(() => {});
if (response?.status === 200) {
emit('change', response?.status === 200);
if ((window as any).onTabSaveSuccess) {
if (response.result?.id) {
(window as any).onTabSaveSuccess(response);
setTimeout(() => window.close(), 300);
}
}
}
loading.value = false;
};

View File

@ -36,6 +36,7 @@
show-search
:filter-option="filterOption"
@change="changeType"
:disabled="!!NetworkType"
/>
</j-form-item>
</j-col>
@ -981,6 +982,7 @@ import {
resourcesCurrent,
supports,
certificates,
start,
} from '@/api/link/type';
import {
FormStates,
@ -1146,13 +1148,21 @@ const saveData = async () => {
: { ...formData.value, ...formRef2Data };
loading.value = true;
const resp =
const resp: any =
id === ':id'
? await save(params).catch(() => {})
: await update({ ...params, id }).catch(() => {});
if (resp?.status === 200) {
message.success('操作成功!');
history.back();
if ((window as any).onTabSaveSuccess) {
if (resp.result?.id) {
start(resp.result?.id).then(() => {
(window as any).onTabSaveSuccess(resp);
setTimeout(() => window.close(), 300);
});
}
}
}
loading.value = false;
};