fix: 加fullpage

This commit is contained in:
100011797 2023-03-30 17:01:58 +08:00
parent 8239b2c308
commit c38923f468
22 changed files with 2263 additions and 2003 deletions

View File

@ -57,7 +57,7 @@ import { getImage } from '@/utils/comm';
<style lang="less" scoped>
.doc {
height: 1000px;
height: 100%;
padding: 24px;
overflow-y: auto;
color: rgba(#000, 0.8);

View File

@ -1,371 +1,418 @@
<template>
<page-container>
<j-card>
<j-row :gutter="24">
<j-col :span="16">
<TitleComponent data="基本信息" />
<j-form
:layout="'vertical'"
ref="formRef"
:model="modelRef"
>
<j-row :gutter="24">
<j-col :span="24">
<j-form-item
label="名称"
name="name"
:rules="[
{
required: true,
message: '请输入名称',
},
{
max: 64,
message: '最多输入64个字符',
},
]"
>
<j-input
placeholder="请输入名称"
v-model:value="modelRef.name"
/>
</j-form-item>
</j-col>
<j-col :span="24">
<j-form-item
:name="['accessConfig', 'regionId']"
:rules="[
{
required: true,
message: '请选择服务地址',
},
]"
>
<template #label>
<span>
服务地址
<j-tooltip
title="阿里云内部给每台机器设置的唯一编号"
>
<AIcon
type="QuestionCircleOutlined"
style="margin-left: 2px"
/>
</j-tooltip>
</span>
</template>
<j-select
placeholder="请选择服务地址"
v-model:value="
modelRef.accessConfig.regionId
"
show-search
@blur="productChange"
>
<j-select-option
v-for="item in regionsList"
:key="item.id"
:value="item.id"
:label="item.name"
>{{ item.name }}</j-select-option
<FullPage>
<j-card>
<div class="box">
<div class="left">
<div class="left-content">
<TitleComponent data="基本信息" />
<j-form
:layout="'vertical'"
ref="formRef"
:model="modelRef"
>
<j-row :gutter="24">
<j-col :span="24">
<j-form-item
label="名称"
name="name"
:rules="[
{
required: true,
message: '请输入名称',
},
{
max: 64,
message: '最多输入64个字符',
},
]"
>
</j-select>
</j-form-item>
</j-col>
<j-col :span="24">
<j-form-item
:name="['accessConfig', 'instanceId']"
>
<template #label>
<span>
实例ID
<j-tooltip
title="阿里云物联网平台中的实例ID,没有则不填"
>
<AIcon
type="QuestionCircleOutlined"
style="margin-left: 2px"
/>
</j-tooltip>
</span>
</template>
<j-input
placeholder="请输入实例ID"
v-model:value="
modelRef.accessConfig.instanceId
"
@blur="productChange"
/>
</j-form-item>
</j-col>
<j-col :span="24">
<j-form-item
:name="['accessConfig', 'accessKeyId']"
:rules="[
{
required: true,
message: '请输入accessKey',
},
{
max: 64,
message: '最多输入64个字符',
},
]"
>
<template #label>
<span>
accessKey
<j-tooltip
title="用于程序通知方式调用云服务API的用户标识"
>
<AIcon
type="QuestionCircleOutlined"
style="margin-left: 2px"
/>
</j-tooltip>
</span>
</template>
<j-input
placeholder="请输入accessKey"
v-model:value="
modelRef.accessConfig.accessKeyId
"
@blur="productChange"
/>
</j-form-item>
</j-col>
<j-col :span="24">
<j-form-item
:name="['accessConfig', 'accessSecret']"
:rules="[
{
required: true,
message: '请输入accessSecret',
},
{
max: 64,
message: '最多输入64个字符',
},
]"
>
<template #label>
<span>
accessSecret
<j-tooltip
title="用于程序通知方式调用云服务费API的秘钥标识"
>
<AIcon
type="QuestionCircleOutlined"
style="margin-left: 2px"
/>
</j-tooltip>
</span>
</template>
<j-input
placeholder="请输入accessSecret"
v-model:value="
modelRef.accessConfig.accessSecret
"
@blur="productChange"
/>
</j-form-item>
</j-col>
<j-col :span="24">
<j-form-item
name="bridgeProductKey"
:rules="{
required: true,
message: '请选择网桥产品',
}"
>
<template #label>
<span>
网桥产品
<j-tooltip
title="物联网平台对应的阿里云产品"
>
<AIcon
type="QuestionCircleOutlined"
style="margin-left: 2px"
/>
</j-tooltip>
</span>
</template>
<j-select
placeholder="请选择网桥产品"
v-model:value="
modelRef.bridgeProductKey
"
show-search
>
<j-select-option
v-for="item in aliyunProductList"
:key="item.productKey"
:value="item.productKey"
:label="item.productName"
>{{
item.productName
}}</j-select-option
<j-input
placeholder="请输入名称"
v-model:value="modelRef.name"
/>
</j-form-item>
</j-col>
<j-col :span="24">
<j-form-item
:name="['accessConfig', 'regionId']"
:rules="[
{
required: true,
message: '请选择服务地址',
},
]"
>
</j-select>
</j-form-item>
</j-col>
<j-col :span="24">
<p>产品映射</p>
<j-collapse
v-if="modelRef.mappings.length"
:activeKey="activeKey"
@change="onCollChange"
>
<j-collapse-panel
v-for="(
item, index
) in modelRef.mappings"
:key="index"
:header="
item.productKey
? (aliyunProductList.find(
(i) =>
i.productKey ===
item.productKey,
)?.productName || `产品映射${index + 1}`)
: `产品映射${index + 1}`
"
>
<template #extra
><AIcon
type="DeleteOutlined"
@click="delItem(index)"
/></template>
<j-row :gutter="24">
<j-col :span="12">
<j-form-item
label="阿里云产品"
:name="[
'mappings',
index,
'productKey',
]"
:rules="{
required: true,
message:
'请选择阿里云产品',
}"
>
<j-select
placeholder="请选择阿里云产品"
v-model:value="
item.productKey
"
show-search
<template #label>
<span>
服务地址
<j-tooltip
title="阿里云内部给每台机器设置的唯一编号"
>
<j-select-option
v-for="i in getAliyunProductList(
item?.productKey || ''
)"
:key="i.productKey"
:value="
i.productKey
<AIcon
type="QuestionCircleOutlined"
style="
margin-left: 2px;
"
:label="
i.productName
"
>{{
i.productName
}}</j-select-option
>
</j-select>
</j-form-item>
</j-col>
<j-col :span="12">
<j-form-item
label="平台产品"
:name="[
'mappings',
index,
'productId',
]"
:rules="{
required: true,
message:
'请选择平台产品',
}"
/>
</j-tooltip>
</span>
</template>
<j-select
placeholder="请选择服务地址"
v-model:value="
modelRef.accessConfig
.regionId
"
show-search
@blur="productChange"
>
<j-select-option
v-for="item in regionsList"
:key="item.id"
:value="item.id"
:label="item.name"
>{{
item.name
}}</j-select-option
>
<j-select
placeholder="请选择平台产品"
v-model:value="
item.productId
"
show-search
</j-select>
</j-form-item>
</j-col>
<j-col :span="24">
<j-form-item
:name="[
'accessConfig',
'instanceId',
]"
>
<template #label>
<span>
实例ID
<j-tooltip
title="阿里云物联网平台中的实例ID,没有则不填"
>
<j-select-option
v-for="i in getPlatProduct(
item.productId || ''
)"
:key="i.id"
:value="i?.id"
:label="i.name"
>{{
i.name
}}</j-select-option
<AIcon
type="QuestionCircleOutlined"
style="
margin-left: 2px;
"
/>
</j-tooltip>
</span>
</template>
<j-input
placeholder="请输入实例ID"
v-model:value="
modelRef.accessConfig
.instanceId
"
@blur="productChange"
/>
</j-form-item>
</j-col>
<j-col :span="24">
<j-form-item
:name="[
'accessConfig',
'accessKeyId',
]"
:rules="[
{
required: true,
message: '请输入accessKey',
},
{
max: 64,
message: '最多输入64个字符',
},
]"
>
<template #label>
<span>
accessKey
<j-tooltip
title="用于程序通知方式调用云服务API的用户标识"
>
<AIcon
type="QuestionCircleOutlined"
style="
margin-left: 2px;
"
/>
</j-tooltip>
</span>
</template>
<j-input
placeholder="请输入accessKey"
v-model:value="
modelRef.accessConfig
.accessKeyId
"
@blur="productChange"
/>
</j-form-item>
</j-col>
<j-col :span="24">
<j-form-item
:name="[
'accessConfig',
'accessSecret',
]"
:rules="[
{
required: true,
message:
'请输入accessSecret',
},
{
max: 64,
message: '最多输入64个字符',
},
]"
>
<template #label>
<span>
accessSecret
<j-tooltip
title="用于程序通知方式调用云服务费API的秘钥标识"
>
<AIcon
type="QuestionCircleOutlined"
style="
margin-left: 2px;
"
/>
</j-tooltip>
</span>
</template>
<j-input
placeholder="请输入accessSecret"
v-model:value="
modelRef.accessConfig
.accessSecret
"
@blur="productChange"
/>
</j-form-item>
</j-col>
<j-col :span="24">
<j-form-item
name="bridgeProductKey"
:rules="{
required: true,
message: '请选择网桥产品',
}"
>
<template #label>
<span>
网桥产品
<j-tooltip
title="物联网平台对应的阿里云产品"
>
<AIcon
type="QuestionCircleOutlined"
style="
margin-left: 2px;
"
/>
</j-tooltip>
</span>
</template>
<j-select
placeholder="请选择网桥产品"
v-model:value="
modelRef.bridgeProductKey
"
show-search
>
<j-select-option
v-for="item in aliyunProductList"
:key="item.productKey"
:value="item.productKey"
:label="item.productName"
>{{
item.productName
}}</j-select-option
>
</j-select>
</j-form-item>
</j-col>
<j-col :span="24">
<p>产品映射</p>
<j-collapse
v-if="modelRef.mappings.length"
:activeKey="activeKey"
@change="onCollChange"
>
<j-collapse-panel
v-for="(
item, index
) in modelRef.mappings"
:key="index"
:header="
item.productKey
? aliyunProductList.find(
(i) =>
i.productKey ===
item.productKey,
)?.productName ||
`产品映射${index + 1}`
: `产品映射${index + 1}`
"
>
<template #extra
><AIcon
type="DeleteOutlined"
@click="delItem(index)"
/></template>
<j-row :gutter="24">
<j-col :span="12">
<j-form-item
label="阿里云产品"
:name="[
'mappings',
index,
'productKey',
]"
:rules="{
required: true,
message:
'请选择阿里云产品',
}"
>
</j-select>
</j-form-item>
</j-col>
</j-row>
</j-collapse-panel>
</j-collapse>
<j-card v-else>
<j-empty />
</j-card>
</j-col>
<j-col :span="24">
<j-button
type="dashed"
style="width: 100%; margin-top: 10px"
@click="addItem"
<j-select
placeholder="请选择阿里云产品"
v-model:value="
item.productKey
"
show-search
>
<j-select-option
v-for="i in getAliyunProductList(
item?.productKey ||
'',
)"
:key="
i.productKey
"
:value="
i.productKey
"
:label="
i.productName
"
>{{
i.productName
}}</j-select-option
>
</j-select>
</j-form-item>
</j-col>
<j-col :span="12">
<j-form-item
label="平台产品"
:name="[
'mappings',
index,
'productId',
]"
:rules="{
required: true,
message:
'请选择平台产品',
}"
>
<j-select
placeholder="请选择平台产品"
v-model:value="
item.productId
"
show-search
>
<j-select-option
v-for="i in getPlatProduct(
item.productId ||
'',
)"
:key="i.id"
:value="
i?.id
"
:label="
i.name
"
>{{
i.name
}}</j-select-option
>
</j-select>
</j-form-item>
</j-col>
</j-row>
</j-collapse-panel>
</j-collapse>
<j-card v-else>
<j-empty />
</j-card>
</j-col>
<j-col :span="24">
<j-button
type="dashed"
style="
width: 100%;
margin-top: 10px;
"
@click="addItem"
>
<AIcon
type="PlusOutlined"
style="margin-left: 2px"
/>
</j-button>
</j-col>
<j-col :span="24" style="margin-top: 20px">
<j-form-item
label="说明"
name="description"
:rules="{
max: 200,
message: '最多输入200个字符',
}"
>
<j-textarea
v-model:value="
modelRef.description
"
placeholder="请输入说明"
showCount
:maxlength="200"
/>
</j-form-item>
</j-col>
</j-row>
</j-form>
<div v-if="type === 'edit'">
<PermissionButton
type="primary"
:loading="loading"
@click="saveBtn"
:hasPermission="[
'Northbound/AliCloud:add',
'Northbound/AliCloud:update',
]"
>
<AIcon
type="PlusOutlined"
style="margin-left: 2px"
/>
</j-button>
</j-col>
<j-col :span="24" style="margin-top: 20px">
<j-form-item
label="说明"
name="description"
:rules="{
max: 200,
message: '最多输入200个字符',
}"
>
<j-textarea
v-model:value="modelRef.description"
placeholder="请输入说明"
showCount
:maxlength="200"
/>
</j-form-item>
</j-col>
</j-row>
</j-form>
<div v-if="type === 'edit'">
<PermissionButton
type="primary"
:loading="loading"
@click="saveBtn"
:hasPermission="['Northbound/AliCloud:add', 'Northbound/AliCloud:update']"
>
保存
</PermissionButton>
保存
</PermissionButton>
</div>
</div>
</div>
</j-col>
<j-col :span="8">
<Doc />
</j-col>
</j-row>
</j-card>
<div class="right">
<Doc />
</div>
</div>
</j-card>
</FullPage>
</page-container>
</template>
@ -489,14 +536,16 @@ const saveBtn = () => {
.validate()
.then(async (data: any) => {
const product = (aliyunProductList.value || []).find(
(item: any) =>
item?.productKey === data?.bridgeProductKey,
(item: any) => item?.productKey === data?.bridgeProductKey,
);
data.bridgeProductName = product?.productName || '';
loading.value = true;
const resp = await savePatch({...toRaw(modelRef), ...data}).finally(() => {
const resp = await savePatch({
...toRaw(modelRef),
...data,
}).finally(() => {
loading.value = false;
})
});
if (resp.status === 200) {
message.success('操作成功!');
formRef.value.resetFields();
@ -539,4 +588,23 @@ watch(
},
{ immediate: true, deep: true },
);
</script>
</script>
<style scoped lang="less">
.box {
position: relative;
.left {
.left-content {
width: 66%;
}
}
.right {
width: 33%;
position: absolute;
right: 0;
top: 0;
overflow-y: auto;
height: 100%;
}
}
</style>

View File

@ -5,119 +5,133 @@
target="northbound-aliyun"
@search="handleSearch"
/>
<JProTable
ref="instanceRef"
:columns="columns"
:request="query"
:defaultParams="{ sorts: [{ name: 'createTime', order: 'desc' }] }"
:params="params"
>
<template #headerTitle>
<j-space>
<PermissionButton
type="primary"
@click="handleAdd"
hasPermission="Northbound/AliCloud:add"
<FullPage>
<JProTable
ref="instanceRef"
:columns="columns"
:request="query"
:defaultParams="{
sorts: [{ name: 'createTime', order: 'desc' }],
}"
:params="params"
>
<template #headerTitle>
<j-space>
<PermissionButton
type="primary"
@click="handleAdd"
hasPermission="Northbound/AliCloud:add"
>
<template #icon
><AIcon type="PlusOutlined"
/></template>
新增
</PermissionButton>
</j-space>
</template>
<template #card="slotProps">
<CardBox
:value="slotProps"
@click="handleView(slotProps.id)"
:actions="getActions(slotProps, 'card')"
:status="slotProps.state?.value"
:statusText="slotProps.state?.text"
:statusNames="{
enabled: 'processing',
disabled: 'error',
}"
>
<template #icon><AIcon type="PlusOutlined" /></template>
新增
</PermissionButton>
</j-space>
</template>
<template #card="slotProps">
<CardBox
:value="slotProps"
@click="handleView(slotProps.id)"
:actions="getActions(slotProps, 'card')"
:status="slotProps.state?.value"
:statusText="slotProps.state?.text"
:statusNames="{
enabled: 'processing',
disabled: 'error',
}"
>
<template #img>
<img :src="getImage('/northbound/aliyun.png')" />
</template>
<template #content>
<Ellipsis style="width: calc(100% - 100px)">
<span style="font-size: 16px; font-weight: 600">
{{ slotProps.name }}
</span>
</Ellipsis>
<j-row style="margin-top: 15px">
<j-col :span="12">
<div class="card-item-content-text">
网桥产品
</div>
<Ellipsis>
<div>
{{ slotProps?.bridgeProductName }}
<template #img>
<img :src="getImage('/northbound/aliyun.png')" />
</template>
<template #content>
<Ellipsis style="width: calc(100% - 100px)">
<span style="font-size: 16px; font-weight: 600">
{{ slotProps.name }}
</span>
</Ellipsis>
<j-row style="margin-top: 15px">
<j-col :span="12">
<div class="card-item-content-text">
网桥产品
</div>
</Ellipsis>
</j-col>
<j-col :span="12">
<div class="card-item-content-text">
<label>说明</label>
</div>
<Ellipsis>
<div>{{ slotProps?.description }}</div>
</Ellipsis>
</j-col>
</j-row>
</template>
<template #actions="item">
<PermissionButton
:disabled="item.disabled"
:popConfirm="item.popConfirm"
:tooltip="item.tooltip"
@click="item.onClick"
:hasPermission="'Northbound/AliCloud:' + item.key"
<Ellipsis>
<div>
{{ slotProps?.bridgeProductName }}
</div>
</Ellipsis>
</j-col>
<j-col :span="12">
<div class="card-item-content-text">
<label>说明</label>
</div>
<Ellipsis>
<div>{{ slotProps?.description }}</div>
</Ellipsis>
</j-col>
</j-row>
</template>
<template #actions="item">
<PermissionButton
:disabled="item.disabled"
:popConfirm="item.popConfirm"
:tooltip="item.tooltip"
@click="item.onClick"
:hasPermission="
'Northbound/AliCloud:' + 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 #state="slotProps">
<BadgeStatus
:status="slotProps.state?.value"
:text="slotProps.state?.text"
:statusNames="{
enabled: 'processing',
disabled: 'error',
}"
/>
</template>
<template #action="slotProps">
<j-space>
<template
v-for="i in getActions(slotProps, 'table')"
:key="i.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 #state="slotProps">
<BadgeStatus
:status="slotProps.state?.value"
:text="slotProps.state?.text"
:statusNames="{
enabled: 'processing',
disabled: 'error',
}"
/>
</template>
<template #action="slotProps">
<j-space>
<template
v-for="i in getActions(slotProps, 'table')"
:key="i.key"
>
<PermissionButton
:disabled="i.disabled"
:popConfirm="i.popConfirm"
:tooltip="i.tooltip"
style="padding: 0 5px"
@click="i.onClick"
type="link"
:danger="i.key === 'delete'"
:hasPermission="i.key === 'view' ? true : 'Northbound/AliCloud:' + i.key"
>
<template #icon><AIcon :type="i.icon" /></template>
</PermissionButton>
</template>
</j-space>
</template>
</JProTable>
<PermissionButton
:disabled="i.disabled"
:popConfirm="i.popConfirm"
:tooltip="i.tooltip"
style="padding: 0 5px"
@click="i.onClick"
type="link"
:danger="i.key === 'delete'"
:hasPermission="
i.key === 'view'
? true
: 'Northbound/AliCloud:' + i.key
"
>
<template #icon
><AIcon :type="i.icon"
/></template>
</PermissionButton>
</template>
</j-space>
</template>
</JProTable>
</FullPage>
</page-container>
</template>

View File

@ -64,7 +64,7 @@ import { getImage } from '@/utils/comm';
<style lang="less" scoped>
.doc {
height: 1000px;
height: 100%;
padding: 24px;
overflow-y: auto;
color: rgba(#000, 0.8);

View File

@ -1,437 +1,479 @@
<template>
<page-container>
<j-card>
<j-row :gutter="24">
<j-col :span="16">
<TitleComponent data="基本信息" />
<j-form
:layout="'vertical'"
ref="formRef"
:model="modelRef"
>
<j-row :gutter="24">
<j-col :span="24">
<j-form-item
label="名称"
name="name"
:rules="[
{
required: true,
message: '请输入名称',
},
{
max: 64,
message: '最多输入64个字符',
},
<FullPage>
<j-card>
<div class="box">
<div class="left">
<div class="left-content">
<TitleComponent data="基本信息" />
<j-form
:layout="'vertical'"
ref="formRef"
:model="modelRef"
>
<j-row :gutter="24">
<j-col :span="24">
<j-form-item
label="名称"
name="name"
:rules="[
{
required: true,
message: '请输入名称',
},
{
max: 64,
message: '最多输入64个字符',
},
]"
>
<j-input
placeholder="请输入名称"
v-model:value="modelRef.name"
/>
</j-form-item>
</j-col>
<j-col :span="12">
<j-form-item
label="产品"
name="id"
:rules="[
{
required: true,
message: '请选择产品',
},
]"
>
<j-select
:disabled="
type !== 'edit' &&
modelRef.id &&
modelRef.id !== ':id'
"
placeholder="请选择产品"
v-model:value="modelRef.id"
show-search
@change="productChange"
>
<j-select-option
v-for="item in productList"
:key="item.id"
:value="item.id"
:label="item.name"
>{{
item.name
}}</j-select-option
>
</j-select>
</j-form-item>
</j-col>
<j-col :span="12">
<j-form-item
name="applianceType"
:rules="{
required: true,
message: '请选择设备类型',
}"
>
<template #label>
<span>
设备类型
<j-tooltip
title="DuerOS平台拟定的规范"
>
<AIcon
type="QuestionCircleOutlined"
style="
margin-left: 2px;
"
/>
</j-tooltip>
</span>
</template>
<j-select
placeholder="请选择设备类型"
v-model:value="
modelRef.applianceType
"
show-search
@change="typeChange"
>
<j-select-option
v-for="item in typeList"
:key="item.id"
:value="item.id"
:label="item.name"
>{{
item.name
}}</j-select-option
>
</j-select>
</j-form-item>
<j-form-item
name="productName"
v-show="false"
label="产品名称"
>
<j-input
v-model:value="
modelRef.productName
"
/>
</j-form-item>
</j-col>
<j-col :span="24">
<p>动作映射</p>
<j-collapse
v-if="
modelRef.actionMappings.length
"
:activeKey="actionActiveKey"
@change="onActionCollChange"
>
<j-collapse-panel
v-for="(
item, index
) in modelRef.actionMappings"
:key="index"
:header="
item.action
? getTypesActions(
item.action,
).find(
(i) =>
i.id ===
item.action,
)?.name
: `动作映射${index + 1}`
"
>
<template #extra
><AIcon
type="DeleteOutlined"
@click="delItem(index)"
/></template>
<j-row :gutter="24">
<j-col :span="12">
<j-form-item
:name="[
'actionMappings',
index,
'action',
]"
:rules="{
required: true,
message:
'请选择动作',
}"
>
<template #label>
<span>
动作
<j-tooltip
title="DuerOS平台拟定的设备类型具有的相关动作"
>
<AIcon
type="QuestionCircleOutlined"
/>
</j-tooltip>
</span>
</template>
<j-select
placeholder="请选择动作"
v-model:value="
item.action
"
show-search
>
<j-select-option
v-for="i in getTypesActions(
item.action ||
'',
)"
:key="i.id"
:value="
i.id
"
:label="
i.name
"
>{{
i.name
}}</j-select-option
>
</j-select>
</j-form-item>
</j-col>
<j-col :span="12">
<j-form-item
:name="[
'actionMappings',
index,
'actionType',
]"
:rules="{
required: true,
message:
'请选择操作',
}"
>
<template #label>
<span>
操作
<j-tooltip
title="映射物联网平台中所选产品具备的动作"
>
<AIcon
type="QuestionCircleOutlined"
/>
</j-tooltip>
</span>
</template>
<j-select
placeholder="请选择操作"
v-model:value="
item.actionType
"
show-search
@change="
() =>
onActionTypeChange(
index,
)
"
>
<j-select-option
value="command"
>下发指令</j-select-option
>
<j-select-option
value="latestData"
>获取历史数据</j-select-option
>
</j-select>
</j-form-item>
</j-col>
<j-col
:span="24"
v-if="item.actionType"
>
<j-form-item
:name="[
'actionMappings',
index,
'command',
]"
>
<Command
ref="command"
:metadata="
findProductMetadata
"
v-model:modelValue="
item.command
"
:actionType="
item.actionType
"
/>
</j-form-item>
</j-col>
</j-row>
</j-collapse-panel>
</j-collapse>
<j-card v-else>
<j-empty />
</j-card>
</j-col>
<j-col :span="24">
<j-button
type="dashed"
style="
width: 100%;
margin-top: 10px;
"
@click="addItem"
>
<AIcon
type="PlusOutlined"
style="margin-left: 2px"
/>
</j-button>
</j-col>
<j-col :span="24">
<p style="margin-top: 20px">属性映射</p>
<j-collapse
v-if="
modelRef.propertyMappings.length
"
:activeKey="propertyActiveKey"
@change="onPropertyCollChange"
>
<j-collapse-panel
v-for="(
item, index
) in modelRef.propertyMappings"
:key="index"
:header="
item.source
? getDuerOSProperties(
item.source,
).find(
(i) =>
i.id ===
item.source,
)?.name
: `属性映射${index + 1}`
"
>
<template #extra
><AIcon
type="DeleteOutlined"
@click="
delPropertyItem(
index,
)
"
/></template>
<j-row :gutter="24">
<j-col :span="12">
<j-form-item
label="DuerOS属性"
:name="[
'propertyMappings',
index,
'source',
]"
:rules="{
required: true,
message:
'请选择DuerOS属性',
}"
>
<j-select
placeholder="请选择DuerOS属性"
v-model:value="
item.source
"
show-search
>
<j-select-option
v-for="i in getDuerOSProperties(
item.source ||
'',
)"
:key="i.id"
:value="
i.id
"
>{{
i.name
}}</j-select-option
>
</j-select>
</j-form-item>
</j-col>
<j-col :span="12">
<j-form-item
label="平台属性"
:name="[
'propertyMappings',
index,
'target',
]"
:rules="{
required: true,
message:
'请选择平台属性',
}"
>
<j-select
placeholder="请选择平台属性"
v-model:value="
item.target
"
mode="tags"
show-search
>
<j-select-option
v-for="i in getProductProperties(
item.target,
)"
:key="i.id"
:value="
i.id
"
>{{
i.name
}}</j-select-option
>
</j-select>
</j-form-item>
</j-col>
</j-row>
</j-collapse-panel>
</j-collapse>
<j-card v-else>
<j-empty />
</j-card>
</j-col>
<j-col :span="24">
<j-button
type="dashed"
style="
width: 100%;
margin-top: 10px;
"
@click="addPropertyItem"
>
<AIcon
type="PlusOutlined"
style="margin-left: 2px"
/>
</j-button>
</j-col>
<j-col :span="24" style="margin-top: 20px">
<j-form-item
label="说明"
name="description"
:rules="{
max: 200,
message: '最多输入200个字符',
}"
>
<j-textarea
v-model:value="
modelRef.description
"
placeholder="请输入说明"
showCount
:maxlength="200"
/>
</j-form-item>
</j-col>
</j-row>
</j-form>
<div v-if="type === 'edit'">
<PermissionButton
type="primary"
:loading="loading"
@click="saveBtn"
:hasPermission="[
'Northbound/DuerOS:add',
'Northbound/DuerOS:update',
]"
>
<j-input
placeholder="请输入名称"
v-model:value="modelRef.name"
/>
</j-form-item>
</j-col>
<j-col :span="12">
<j-form-item
label="产品"
name="id"
:rules="[
{
required: true,
message: '请选择产品',
},
]"
>
<j-select
:disabled="
type !== 'edit' &&
modelRef.id &&
modelRef.id !== ':id'
"
placeholder="请选择产品"
v-model:value="modelRef.id"
show-search
@change="productChange"
>
<j-select-option
v-for="item in productList"
:key="item.id"
:value="item.id"
:label="item.name"
>{{ item.name }}</j-select-option
>
</j-select>
</j-form-item>
</j-col>
<j-col :span="12">
<j-form-item
name="applianceType"
:rules="{
required: true,
message: '请选择设备类型',
}"
>
<template #label>
<span>
设备类型
<j-tooltip
title="DuerOS平台拟定的规范"
>
<AIcon
type="QuestionCircleOutlined"
style="margin-left: 2px"
/>
</j-tooltip>
</span>
</template>
<j-select
placeholder="请选择设备类型"
v-model:value="modelRef.applianceType"
show-search
@change="typeChange"
>
<j-select-option
v-for="item in typeList"
:key="item.id"
:value="item.id"
:label="item.name"
>{{ item.name }}</j-select-option
>
</j-select>
</j-form-item>
<j-form-item
name="productName"
v-show="false"
label="产品名称"
>
<j-input
v-model:value="modelRef.productName"
/>
</j-form-item>
</j-col>
<j-col :span="24">
<p>动作映射</p>
<j-collapse
v-if="modelRef.actionMappings.length"
:activeKey="actionActiveKey"
@change="onActionCollChange"
>
<j-collapse-panel
v-for="(
item, index
) in modelRef.actionMappings"
:key="index"
:header="
item.action
? getTypesActions(
item.action,
).find(
(i) =>
i.id === item.action,
)?.name
: `动作映射${index + 1}`
"
>
<template #extra
><AIcon
type="DeleteOutlined"
@click="delItem(index)"
/></template>
<j-row :gutter="24">
<j-col :span="12">
<j-form-item
:name="[
'actionMappings',
index,
'action',
]"
:rules="{
required: true,
message: '请选择动作',
}"
>
<template #label>
<span>
动作
<j-tooltip
title="DuerOS平台拟定的设备类型具有的相关动作"
>
<AIcon
type="QuestionCircleOutlined"
/>
</j-tooltip>
</span>
</template>
<j-select
placeholder="请选择动作"
v-model:value="
item.action
"
show-search
>
<j-select-option
v-for="i in getTypesActions(
item.action ||
'',
)"
:key="i.id"
:value="i.id"
:label="i.name"
>{{
i.name
}}</j-select-option
>
</j-select>
</j-form-item>
</j-col>
<j-col :span="12">
<j-form-item
:name="[
'actionMappings',
index,
'actionType',
]"
:rules="{
required: true,
message: '请选择操作',
}"
>
<template #label>
<span>
操作
<j-tooltip
title="映射物联网平台中所选产品具备的动作"
>
<AIcon
type="QuestionCircleOutlined"
/>
</j-tooltip>
</span>
</template>
<j-select
placeholder="请选择操作"
v-model:value="
item.actionType
"
show-search
@change="
() =>
onActionTypeChange(
index,
)
"
>
<j-select-option
value="command"
>下发指令</j-select-option
>
<j-select-option
value="latestData"
>获取历史数据</j-select-option
>
</j-select>
</j-form-item>
</j-col>
<j-col
:span="24"
v-if="item.actionType"
>
<j-form-item
:name="[
'actionMappings',
index,
'command',
]"
>
<Command
ref="command"
:metadata="
findProductMetadata
"
v-model:modelValue="
item.command
"
:actionType="
item.actionType
"
/>
</j-form-item>
</j-col>
</j-row>
</j-collapse-panel>
</j-collapse>
<j-card v-else>
<j-empty />
</j-card>
</j-col>
<j-col :span="24">
<j-button
type="dashed"
style="width: 100%; margin-top: 10px"
@click="addItem"
>
<AIcon
type="PlusOutlined"
style="margin-left: 2px"
/>
</j-button>
</j-col>
<j-col :span="24">
<p style="margin-top: 20px">属性映射</p>
<j-collapse
v-if="modelRef.propertyMappings.length"
:activeKey="propertyActiveKey"
@change="onPropertyCollChange"
>
<j-collapse-panel
v-for="(
item, index
) in modelRef.propertyMappings"
:key="index"
:header="
item.source
? getDuerOSProperties(
item.source,
).find(
(i) =>
i.id === item.source,
)?.name
: `属性映射${index + 1}`
"
>
<template #extra
><AIcon
type="DeleteOutlined"
@click="delPropertyItem(index)"
/></template>
<j-row :gutter="24">
<j-col :span="12">
<j-form-item
label="DuerOS属性"
:name="[
'propertyMappings',
index,
'source',
]"
:rules="{
required: true,
message:
'请选择DuerOS属性',
}"
>
<j-select
placeholder="请选择DuerOS属性"
v-model:value="
item.source
"
show-search
>
<j-select-option
v-for="i in getDuerOSProperties(
item.source ||
'',
)"
:key="i.id"
:value="i.id"
>{{
i.name
}}</j-select-option
>
</j-select>
</j-form-item>
</j-col>
<j-col :span="12">
<j-form-item
label="平台属性"
:name="[
'propertyMappings',
index,
'target',
]"
:rules="{
required: true,
message:
'请选择平台属性',
}"
>
<j-select
placeholder="请选择平台属性"
v-model:value="
item.target
"
mode="tags"
show-search
>
<j-select-option
v-for="i in getProductProperties(
item.target,
)"
:key="i.id"
:value="i.id"
>{{
i.name
}}</j-select-option
>
</j-select>
</j-form-item>
</j-col>
</j-row>
</j-collapse-panel>
</j-collapse>
<j-card v-else>
<j-empty />
</j-card>
</j-col>
<j-col :span="24">
<j-button
type="dashed"
style="width: 100%; margin-top: 10px"
@click="addPropertyItem"
>
<AIcon
type="PlusOutlined"
style="margin-left: 2px"
/>
</j-button>
</j-col>
<j-col :span="24" style="margin-top: 20px">
<j-form-item
label="说明"
name="description"
:rules="{
max: 200,
message: '最多输入200个字符',
}"
>
<j-textarea
v-model:value="modelRef.description"
placeholder="请输入说明"
showCount
:maxlength="200"
/>
</j-form-item>
</j-col>
</j-row>
</j-form>
<div v-if="type === 'edit'">
<PermissionButton
type="primary"
:loading="loading"
@click="saveBtn"
:hasPermission="[
'Northbound/DuerOS:add',
'Northbound/DuerOS:update',
]"
>
保存
</PermissionButton>
保存
</PermissionButton>
</div>
</div>
</div>
</j-col>
<j-col :span="8">
<Doc />
</j-col>
</j-row>
</j-card>
<div class="right">
<Doc />
</div>
</div>
</j-card>
</FullPage>
</page-container>
</template>
@ -504,7 +546,7 @@ const onActionTypeChange = (_index: number) => {
properties: undefined,
functionId: undefined,
inputs: [],
value: undefined
value: undefined,
},
};
};
@ -720,4 +762,23 @@ watch(
},
{ immediate: true, deep: true },
);
</script>
</script>
<style scoped lang="less">
.box {
position: relative;
.left {
.left-content {
width: 66%;
}
}
.right {
width: 33%;
position: absolute;
right: 0;
top: 0;
overflow-y: auto;
height: 100%;
}
}
</style>

View File

@ -5,122 +5,138 @@
target="northbound-dueros"
@search="handleSearch"
/>
<JProTable
ref="instanceRef"
:columns="columns"
:request="query"
:defaultParams="{ sorts: [{ name: 'createTime', order: 'desc' }] }"
:params="params"
>
<template #headerTitle>
<j-space>
<PermissionButton
type="primary"
@click="handleAdd"
hasPermission="Northbound/DuerOS:add"
>
<template #icon><AIcon type="PlusOutlined" /></template>
新增
</PermissionButton>
</j-space>
</template>
<template #card="slotProps">
<CardBox
:value="slotProps"
@click="handleView(slotProps.id)"
:actions="getActions(slotProps, 'card')"
:status="slotProps.state?.value"
:statusText="slotProps.state?.text"
:statusNames="{
enabled: 'processing',
disabled: 'error',
}"
>
<template #img>
<img :src="getImage('/cloud/dueros.png')" />
</template>
<template #content>
<Ellipsis style="width: calc(100% - 100px)">
<span style="font-size: 16px; font-weight: 600">
{{ slotProps.name }}
</span>
</Ellipsis>
<j-row style="margin-top: 15px">
<j-col :span="12">
<div class="card-item-content-text">产品</div>
<Ellipsis>
<div>{{ slotProps?.productName }}</div>
</Ellipsis>
</j-col>
<j-col :span="12">
<div class="card-item-content-text">
设备类型
</div>
<Ellipsis>
<div>{{ slotProps?.applianceType?.text }}</div>
</Ellipsis>
</j-col>
</j-row>
</template>
<template #actions="item">
<FullPage>
<JProTable
ref="instanceRef"
:columns="columns"
:request="query"
:defaultParams="{
sorts: [{ name: 'createTime', order: 'desc' }],
}"
:params="params"
>
<template #headerTitle>
<j-space>
<PermissionButton
:disabled="item.disabled"
:popConfirm="item.popConfirm"
:tooltip="{
...item.tooltip,
}"
@click="item.onClick"
:hasPermission="'Northbound/DuerOS:' + item.key"
type="primary"
@click="handleAdd"
hasPermission="Northbound/DuerOS:add"
>
<AIcon
type="DeleteOutlined"
v-if="item.key === 'delete'"
/>
<template v-else>
<AIcon :type="item.icon" />
<span>{{ item?.text }}</span>
</template>
<template #icon
><AIcon type="PlusOutlined"
/></template>
新增
</PermissionButton>
</template>
</CardBox>
</template>
<template #state="slotProps">
<BadgeStatus
:status="slotProps.state?.value"
:text="slotProps.state?.text"
:statusNames="{
enabled: 'processing',
disabled: 'error',
}"
/>
</template>
<template #applianceType="slotProps">
{{ slotProps.applianceType.text }}
</template>
<template #action="slotProps">
<j-space>
<template
v-for="i in getActions(slotProps, 'table')"
:key="i.key"
</j-space>
</template>
<template #card="slotProps">
<CardBox
:value="slotProps"
@click="handleView(slotProps.id)"
:actions="getActions(slotProps, 'card')"
:status="slotProps.state?.value"
:statusText="slotProps.state?.text"
:statusNames="{
enabled: 'processing',
disabled: 'error',
}"
>
<PermissionButton
:disabled="i.disabled"
:popConfirm="i.popConfirm"
:tooltip="{
...i.tooltip,
}"
style="padding: 0 5px"
@click="i.onClick"
type="link"
:danger="i.key === 'delete'"
:hasPermission="i.key === 'view' ? true : 'Northbound/DuerOS:' + i.key"
<template #img>
<img :src="getImage('/cloud/dueros.png')" />
</template>
<template #content>
<Ellipsis style="width: calc(100% - 100px)">
<span style="font-size: 16px; font-weight: 600">
{{ slotProps.name }}
</span>
</Ellipsis>
<j-row style="margin-top: 15px">
<j-col :span="12">
<div class="card-item-content-text">
产品
</div>
<Ellipsis>
<div>{{ slotProps?.productName }}</div>
</Ellipsis>
</j-col>
<j-col :span="12">
<div class="card-item-content-text">
设备类型
</div>
<Ellipsis>
<div>
{{ slotProps?.applianceType?.text }}
</div>
</Ellipsis>
</j-col>
</j-row>
</template>
<template #actions="item">
<PermissionButton
:disabled="item.disabled"
:popConfirm="item.popConfirm"
:tooltip="{
...item.tooltip,
}"
@click="item.onClick"
:hasPermission="'Northbound/DuerOS:' + 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 #state="slotProps">
<BadgeStatus
:status="slotProps.state?.value"
:text="slotProps.state?.text"
:statusNames="{
enabled: 'processing',
disabled: 'error',
}"
/>
</template>
<template #applianceType="slotProps">
{{ slotProps.applianceType.text }}
</template>
<template #action="slotProps">
<j-space>
<template
v-for="i in getActions(slotProps, 'table')"
:key="i.key"
>
<template #icon><AIcon :type="i.icon" /></template>
</PermissionButton>
</template>
</j-space>
</template>
</JProTable>
<PermissionButton
:disabled="i.disabled"
:popConfirm="i.popConfirm"
:tooltip="{
...i.tooltip,
}"
style="padding: 0 5px"
@click="i.onClick"
type="link"
:danger="i.key === 'delete'"
:hasPermission="
i.key === 'view'
? true
: 'Northbound/DuerOS:' + i.key
"
>
<template #icon
><AIcon :type="i.icon"
/></template>
</PermissionButton>
</template>
</j-space>
</template>
</JProTable>
</FullPage>
</page-container>
</template>

View File

@ -1,114 +1,113 @@
<template>
<j-card>
<SaveChild
v-if="childVisible"
@close-child-save="closeChildSave"
:childData="_current"
<SaveChild
v-if="childVisible"
@close-child-save="closeChildSave"
:childData="_current"
/>
<div v-else>
<pro-search
:columns="columns"
target="child-device"
@search="handleSearch"
class="device-child-device-search"
/>
<div v-else>
<pro-search
:columns="columns"
target="child-device"
@search="handleSearch"
class="child-device-search"
/>
<JProTable
ref="childDeviceRef"
:columns="columns"
:request="query"
:defaultParams="{
terms: [
{
column: 'parentId',
value: detail?.id || '',
termType: 'eq',
},
],
}"
:rowSelection="{
selectedRowKeys: _selectedRowKeys,
onChange: onSelectChange,
}"
@cancelSelect="cancelSelect"
:params="params"
:model="'TABLE'"
>
<template #headerTitle>
<j-space>
<!-- <j-divider /> -->
<JProTable
ref="childDeviceRef"
:columns="columns"
:request="query"
:bodyStyle="{
padding: 0
}"
:defaultParams="{
terms: [
{
column: 'parentId',
value: detail?.id || '',
termType: 'eq',
},
],
}"
:rowSelection="{
selectedRowKeys: _selectedRowKeys,
onChange: onSelectChange,
}"
@cancelSelect="cancelSelect"
:params="params"
:model="'TABLE'"
>
<template #rightExtraRender>
<j-space>
<PermissionButton
type="primary"
v-if="
detail?.accessProvider === 'official-edge-gateway'
"
hasPermission="device/Instance:update"
@click="
_current = {};
childVisible = true;
"
>新增并绑定</PermissionButton
>
<PermissionButton
type="primary"
@click="visible = true"
hasPermission="device/Instance:update"
>
绑定</PermissionButton
>
<PermissionButton
type="primary"
hasPermission="device/Instance:update"
:popConfirm="{
title: '确定解绑吗?',
onConfirm: handleUnBind,
}"
>批量解除</PermissionButton
>
</j-space>
</template>
<template #registryTime="slotProps">
{{
slotProps.registryTime
? moment(slotProps.registryTime).format(
'YYYY-MM-DD HH:mm:ss',
)
: ''
}}
</template>
<template #state="slotProps">
<j-badge
:text="slotProps.state.text"
:status="statusMap.get(slotProps.state.value)"
/>
</template>
<template #action="slotProps">
<j-space :size="16">
<template
v-for="i in getActions(slotProps, 'table')"
:key="i.key"
>
<PermissionButton
type="primary"
v-if="
detail?.accessProvider ===
'official-edge-gateway'
"
hasPermission="device/Instance:update"
@click="
_current = {};
childVisible = true;
"
>新增并绑定</PermissionButton
>
<PermissionButton
type="primary"
@click="visible = true"
hasPermission="device/Instance:update"
>
绑定</PermissionButton
>
<PermissionButton
type="primary"
hasPermission="device/Instance:update"
:popConfirm="{
title: '确定解绑吗?',
onConfirm: handleUnBind,
:disabled="i.disabled"
:popConfirm="i.popConfirm"
:tooltip="{
...i.tooltip,
}"
>批量解除</PermissionButton
@click="i.onClick"
type="link"
style="padding: 0px"
:hasPermission="'device/Instance:' + i.key"
>
</j-space>
</template>
<template #registryTime="slotProps">
{{
slotProps.registryTime
? moment(slotProps.registryTime).format(
'YYYY-MM-DD HH:mm:ss',
)
: ''
}}
</template>
<template #state="slotProps">
<j-badge
:text="slotProps.state.text"
:status="statusMap.get(slotProps.state.value)"
/>
</template>
<template #action="slotProps">
<j-space :size="16">
<template
v-for="i in getActions(slotProps, 'table')"
:key="i.key"
>
<PermissionButton
:disabled="i.disabled"
:popConfirm="i.popConfirm"
:tooltip="{
...i.tooltip,
}"
@click="i.onClick"
type="link"
style="padding: 0px"
:hasPermission="'device/Instance:' + i.key"
>
<template #icon
><AIcon :type="i.icon"
/></template>
</PermissionButton>
</template>
</j-space>
</template>
</JProTable>
<BindChildDevice v-if="visible" @change="closeBindDevice" />
</div>
</j-card>
<template #icon><AIcon :type="i.icon" /></template>
</PermissionButton>
</template>
</j-space>
</template>
</JProTable>
<BindChildDevice v-if="visible" @change="closeBindDevice" />
</div>
</template>
<script setup lang="ts">
@ -147,10 +146,10 @@ const columns = [
dataIndex: 'id',
key: 'id',
ellipsis: true,
search:{
type:'string',
defaultTermType: 'eq'
}
search: {
type: 'string',
defaultTermType: 'eq',
},
},
{
title: '设备名称',
@ -303,12 +302,8 @@ const closeChildSave = () => {
};
</script>
<style scoped lang="less">
.child-device-search {
border-bottom: 1px solid #f0f0f0;
}
:deep(._jtable-body_1eyxz_1 ._jtable-body-header_1eyxz_6) {
justify-content: flex-end;
<style lang="less">
.device-child-device-search {
padding: 0px;
}
</style>

View File

@ -1,96 +1,84 @@
<template>
<j-card>
<div class="diagnose">
<div
class="diagnose-header"
:style="{ background: headerColorMap.get(topState) }"
>
<div class="diagnose-top">
<div class="diagnose-img">
<div
v-if="topState === 'loading'"
style="
width: 100%;
height: 100%;
position: relative;
"
>
<img
:src="headerImgMap.get(topState)"
style="
height: 100%;
position: absolute;
z-index: 2;
"
/>
<img
:src="getImage('/diagnose/loading-1.png')"
class="diagnose-loading"
style="height: 100%"
/>
</div>
<div class="diagnose">
<div
class="diagnose-header"
:style="{ background: headerColorMap.get(topState) }"
>
<div class="diagnose-top">
<div class="diagnose-img">
<div
v-if="topState === 'loading'"
style="width: 100%; height: 100%; position: relative"
>
<img
v-else
:src="headerImgMap.get(topState)"
style="height: 100%; position: absolute; z-index: 2"
/>
<img
:src="getImage('/diagnose/loading-1.png')"
class="diagnose-loading"
style="height: 100%"
/>
</div>
<div class="diagnose-text">
<div class="diagnose-title">
{{ headerTitleMap.get(topState) }}
</div>
<div class="diagnose-desc">
<template v-if="topState !== 'loading'">{{
headerDescMap.get(topState)
}}</template>
<template v-else>已诊断{{ count }}</template>
</div>
</div>
</div>
<div class="diagnose-progress">
<j-progress
:percent="percent"
:showInfo="false"
size="small"
:strokeColor="progressMap.get(topState)"
style="width: 100%"
<img
v-else
:src="headerImgMap.get(topState)"
style="height: 100%"
/>
</div>
<div class="diagnose-radio">
<div
class="diagnose-radio-item"
:class="
item.key === 'message' && topState !== 'success'
? 'disabled'
: ''
"
v-for="item in tabList"
:key="item.key"
:style="
activeKey === item.key ? { ...activeStyle } : {}
"
@click="onTabChange(item.key)"
>
{{ item.text }}
<div class="diagnose-text">
<div class="diagnose-title">
{{ headerTitleMap.get(topState) }}
</div>
<div class="diagnose-desc">
<template v-if="topState !== 'loading'">{{
headerDescMap.get(topState)
}}</template>
<template v-else>已诊断{{ count }}</template>
</div>
</div>
</div>
<div>
<template v-if="!first">
<Message v-show="activeKey === 'message'" />
</template>
<template v-if="flag">
<Status
v-show="activeKey !== 'message'"
:providerType="providerType"
@countChange="countChange"
@percentChange="percentChange"
@stateChange="stateChange"
/>
</template>
<div class="diagnose-progress">
<j-progress
:percent="percent"
:showInfo="false"
size="small"
:strokeColor="progressMap.get(topState)"
style="width: 100%"
/>
</div>
<div class="diagnose-radio">
<div
class="diagnose-radio-item"
:class="
item.key === 'message' && topState !== 'success'
? 'disabled'
: ''
"
v-for="item in tabList"
:key="item.key"
:style="activeKey === item.key ? { ...activeStyle } : {}"
@click="onTabChange(item.key)"
>
{{ item.text }}
</div>
</div>
</div>
</j-card>
<div>
<template v-if="!first">
<Message v-show="activeKey === 'message'" />
</template>
<template v-if="flag">
<Status
v-show="activeKey !== 'message'"
:providerType="providerType"
@countChange="countChange"
@percentChange="percentChange"
@stateChange="stateChange"
/>
</template>
</div>
</div>
</template>
<script lang="ts" setup>
@ -160,7 +148,7 @@ const countChange = (num: number) => {
};
const init = () => {
flag.value = true
flag.value = true;
activeKey.value = 'status';
const provider = instanceStore.current?.accessProvider;
if (provider === 'fixed-media' || provider === 'gb28181-2016') {
@ -175,16 +163,16 @@ const init = () => {
providerType.value = 'network';
}
topState.value = 'loading';
}
};
onMounted(() => {
setTimeout(() => {
init()
}, 500)
init();
}, 500);
});
onUnmounted(() => {
flag.value = false
flag.value = false;
});
</script>

View File

@ -1,6 +1,6 @@
<template>
<j-spin :spinning="loading" v-if="metadata.properties.length">
<j-card>
<j-card :bordered="false" style="padding: 0">
<template #extra>
<j-space>
<j-button @click="visible = true">批量映射</j-button>
@ -188,7 +188,7 @@
:edgeId="instanceStore.current.parentId"
/>
</j-spin>
<j-card v-else>
<j-card v-else :bordered="false" style="padding: 0">
<JEmpty description="暂无数据,请配置物模型" style="margin: 10% 0" />
</j-card>
</template>

View File

@ -1,23 +1,21 @@
<template>
<j-card>
<j-empty
v-if="!metadata || (metadata && !metadata.functions.length)"
style="margin-top: 50px"
>
<template #description>
请配置对应产品的
<!-- <a @click="emits('onJump', 'Metadata')">物模型属性功能</a> -->
<a @click="onJump">物模型属性功能</a>
</template>
</j-empty>
<template v-else>
<j-tabs v-model:activeKey="activeKey">
<j-tab-pane key="Simple" tab="精简模式" />
<j-tab-pane key="Advance" tab="高级模式" />
</j-tabs>
<component :is="tabs[activeKey]" />
<j-empty
v-if="!metadata || (metadata && !metadata.functions.length)"
style="margin-top: 50px"
>
<template #description>
请配置对应产品的
<!-- <a @click="emits('onJump', 'Metadata')">物模型属性功能</a> -->
<a @click="onJump">物模型属性功能</a>
</template>
</j-card>
</j-empty>
<template v-else>
<j-tabs v-model:activeKey="activeKey">
<j-tab-pane key="Simple" tab="精简模式" />
<j-tab-pane key="Advance" tab="高级模式" />
</j-tabs>
<component :is="tabs[activeKey]" />
</template>
</template>
<script setup lang="ts">

View File

@ -1,90 +1,88 @@
<template>
<j-card>
<j-descriptions bordered>
<template #title>
设备信息
<PermissionButton
type="link"
@click="visible = true"
hasPermission="device/Instance:update"
>
<template #icon><AIcon type="EditOutlined" /></template>
编辑
</PermissionButton>
</template>
<j-descriptions-item label="设备ID">{{
instanceStore.current?.id
}}</j-descriptions-item>
<j-descriptions-item label="产品名称">{{
instanceStore.current?.productName
}}</j-descriptions-item>
<j-descriptions-item label="产品分类">{{
instanceStore.current?.classifiedName
}}</j-descriptions-item>
<j-descriptions-item label="设备类型">{{
instanceStore.current?.deviceType?.text
}}</j-descriptions-item>
<j-descriptions-item label="固件版本">{{
instanceStore.current?.firmwareInfo?.version
}}</j-descriptions-item>
<j-descriptions-item label="连接协议">{{
instanceStore.current?.transport
}}</j-descriptions-item>
<j-descriptions-item label="消息协议">{{
instanceStore.current?.protocolName
}}</j-descriptions-item>
<j-descriptions-item label="创建时间">{{
instanceStore.current?.createTime
? moment(instanceStore.current?.createTime).format(
'YYYY-MM-DD HH:mm:ss',
)
: ''
}}</j-descriptions-item>
<j-descriptions-item label="注册时间">{{
instanceStore.current?.registerTime
? moment(instanceStore.current?.registerTime).format(
'YYYY-MM-DD HH:mm:ss',
)
: ''
}}</j-descriptions-item>
<j-descriptions-item label="最后上线时间">{{
instanceStore.current?.onlineTime
? moment(instanceStore.current?.onlineTime).format(
'YYYY-MM-DD HH:mm:ss',
)
: ''
}}</j-descriptions-item>
<j-descriptions-item
label="父设备"
v-if="
instanceStore.current?.deviceType?.value === 'childrenDevice'
"
>{{ instanceStore.current?.parentId }}</j-descriptions-item
<j-descriptions bordered>
<template #title>
设备信息
<PermissionButton
type="link"
@click="visible = true"
hasPermission="device/Instance:update"
>
<j-descriptions-item label="说明">{{
instanceStore.current?.description
}}</j-descriptions-item>
</j-descriptions>
<Config />
<Tags
<template #icon><AIcon type="EditOutlined" /></template>
编辑
</PermissionButton>
</template>
<j-descriptions-item label="设备ID">{{
instanceStore.current?.id
}}</j-descriptions-item>
<j-descriptions-item label="产品名称">{{
instanceStore.current?.productName
}}</j-descriptions-item>
<j-descriptions-item label="产品分类">{{
instanceStore.current?.classifiedName
}}</j-descriptions-item>
<j-descriptions-item label="设备类型">{{
instanceStore.current?.deviceType?.text
}}</j-descriptions-item>
<j-descriptions-item label="固件版本">{{
instanceStore.current?.firmwareInfo?.version
}}</j-descriptions-item>
<j-descriptions-item label="连接协议">{{
instanceStore.current?.transport
}}</j-descriptions-item>
<j-descriptions-item label="消息协议">{{
instanceStore.current?.protocolName
}}</j-descriptions-item>
<j-descriptions-item label="创建时间">{{
instanceStore.current?.createTime
? moment(instanceStore.current?.createTime).format(
'YYYY-MM-DD HH:mm:ss',
)
: ''
}}</j-descriptions-item>
<j-descriptions-item label="注册时间">{{
instanceStore.current?.registerTime
? moment(instanceStore.current?.registerTime).format(
'YYYY-MM-DD HH:mm:ss',
)
: ''
}}</j-descriptions-item>
<j-descriptions-item label="最后上线时间">{{
instanceStore.current?.onlineTime
? moment(instanceStore.current?.onlineTime).format(
'YYYY-MM-DD HH:mm:ss',
)
: ''
}}</j-descriptions-item>
<j-descriptions-item
label="父设备"
v-if="
instanceStore.current?.tags &&
instanceStore.current?.tags.length > 0
instanceStore.current?.deviceType?.value === 'childrenDevice'
"
/>
<Relation
v-if="
instanceStore.current?.relations &&
instanceStore.current?.relations.length > 0
"
/>
<Save
v-if="visible"
:data="instanceStore.current"
@close="visible = false"
@save="saveBtn"
/>
</j-card>
>{{ instanceStore.current?.parentId }}</j-descriptions-item
>
<j-descriptions-item label="说明">{{
instanceStore.current?.description
}}</j-descriptions-item>
</j-descriptions>
<Config />
<Tags
v-if="
instanceStore.current?.tags &&
instanceStore.current?.tags.length > 0
"
/>
<Relation
v-if="
instanceStore.current?.relations &&
instanceStore.current?.relations.length > 0
"
/>
<Save
v-if="visible"
:data="instanceStore.current"
@close="visible = false"
@save="saveBtn"
/>
</template>
<script lang="ts" setup>

View File

@ -1,51 +1,47 @@
<template>
<j-card>
<pro-search
:columns="columns"
target="device-instance-log"
@search="handleSearch"
type="simple"
class="search"
/>
<JProTable
ref="instanceRefLog"
:columns="columns"
:request="(e: Record<string, any>) => queryLog(instanceStore.current.id, e)"
model="TABLE"
:defaultParams="{ sorts: [{ name: 'timestamp', order: 'desc' }] }"
:params="params"
:bodyStyle="{ padding: 0 }"
>
<template #type="slotProps">
{{ slotProps?.type?.text }}
</template>
<template #timestamp="slotProps">
{{
slotProps.timestamp
? moment(slotProps.timestamp).format(
'YYYY-MM-DD HH:mm:ss',
)
: ''
}}
</template>
<template #action="slotProps">
<j-space>
<template
v-for="i in getActions(slotProps, 'table')"
:key="i.key"
<pro-search
:columns="columns"
target="device-instance-log"
@search="handleSearch"
type="simple"
class="device-log-search"
/>
<JProTable
ref="instanceRefLog"
:columns="columns"
:request="(e: Record<string, any>) => queryLog(instanceStore.current.id, e)"
model="TABLE"
:defaultParams="{ sorts: [{ name: 'timestamp', order: 'desc' }] }"
:params="params"
:bodyStyle="{ padding: 0 }"
>
<template #type="slotProps">
{{ slotProps?.type?.text }}
</template>
<template #timestamp="slotProps">
{{
slotProps.timestamp
? moment(slotProps.timestamp).format('YYYY-MM-DD HH:mm:ss')
: ''
}}
</template>
<template #action="slotProps">
<j-space>
<template
v-for="i in getActions(slotProps, 'table')"
:key="i.key"
>
<j-button
@click="i.onClick"
type="link"
style="padding: 0px"
>
<j-button
@click="i.onClick"
type="link"
style="padding: 0px"
>
<template #icon><AIcon :type="i.icon" /></template>
</j-button>
</template>
</j-space>
</template>
</JProTable>
</j-card>
<template #icon><AIcon :type="i.icon" /></template>
</j-button>
</template>
</j-space>
</template>
</JProTable>
</template>
<script lang="ts" setup>
@ -125,11 +121,7 @@ const getActions = (
onClick: () => {
let content = '';
try {
content = JSON.stringify(
JSON.parse(data.content),
null,
2,
);
content = JSON.stringify(JSON.parse(data.content), null, 2);
} catch (error) {
content = data.content;
}
@ -139,7 +131,7 @@ const getActions = (
content: h(Textarea, {
bordered: false,
rows: 15,
value: content
value: content,
}),
});
},
@ -152,8 +144,8 @@ const handleSearch = (_params: any) => {
};
</script>
<style lang="less" scoped>
.search {
<style lang="less">
.device-log-search {
padding: 0;
}
</style>

View File

@ -1,187 +1,262 @@
<template>
<j-card>
<div>
<div class="top">
<div class="top-left">
<div>
<AIcon type="ExclamationCircleOutlined" />
<template v-if="topTitle === 'rest'">
当前数据解析内容已脱离产品影响
<PermissionButton type="link" hasPermission="device/Instance:update" @click="rest()">
重置
</PermissionButton>
后将继承产品数据解析内容
<div>
<div class="top">
<div class="top-left">
<div>
<AIcon type="ExclamationCircleOutlined" />
<template v-if="topTitle === 'rest'">
当前数据解析内容已脱离产品影响
<PermissionButton
type="link"
hasPermission="device/Instance:update"
@click="rest()"
>
重置
</PermissionButton>
后将继承产品数据解析内容
</template>
<template v-else>
当前数据解析内容继承自产品,
<PermissionButton
type="link"
hasPermission="device/Instance:update"
@click="readOnly = false"
:style="color"
>
修改
</PermissionButton>
后将脱离产品影响
</template>
</div>
</div>
<div>
脚本语言:
<j-select
:defaultValue="'JavaScript'"
style="width: 200px; margin-left: 5px"
>
<j-select-option value="JavaScript"
>JavaScript(ECMAScript 5)</j-select-option
>
</j-select>
<AIcon
type="ExpandOutlined"
style="margin-left: 20px"
@click="toggle"
/>
</div>
</div>
<div class="edit" ref="el">
<div
v-show="readOnly"
class="edit-only"
@click="
() => {
message.warning({
key: 1,
content: () => '请点击上方修改字样,用以编辑脚本',
style: {
marginTop: '260px',
},
});
}
"
></div>
<j-monaco-editor
language="javascript"
style="height: 100%"
theme="vs"
v-model:modelValue="editorValue"
/>
</div>
<div class="bottom">
<div style="width: 49.5%">
<div class="bottom-title">
<div class="bottom-title-text">模拟输入</div>
<div class="bottom-title-topic">
<template
v-if="instanceStore.current.transport === 'MQTT'"
>
<div style="margin-right: 5px">Topic:</div>
<j-auto-complete
placeholder="请输入Topic"
style="width: 300px"
:options="topicList"
:allowClear="true"
:filterOption="filterOption"
v-model:value="topic"
/>
</template>
<template v-else>
当前数据解析内容继承自产品,
<PermissionButton type="link" hasPermission="device/Instance:update" @click="readOnly = false"
:style="color">
修改
</PermissionButton>
后将脱离产品影响
<div style="margin-right: 5px">URL:</div>
<j-input
placeholder="请输入URL"
v-model:value="url"
style="width: 300px"
></j-input>
</template>
</div>
</div>
<div>
脚本语言:
<j-select :defaultValue="'JavaScript'" style="width: 200px;margin-left: 5px;">
<j-select-option value="JavaScript">JavaScript(ECMAScript 5)</j-select-option>
</j-select>
<AIcon type="ExpandOutlined" style="margin-left: 20px;" @click="toggle" />
</div>
<j-textarea
:rows="5"
placeholder="// 二进制数据以0x开头的十六进制输入字符串数据输入原始字符串"
style="margin-top: 10px"
v-model:value="simulation"
/>
</div>
<div class="edit" ref="el">
<div v-show="readOnly" class="edit-only" @click="() => {
message.warning({
key: 1,
content: () => '请点击上方修改字样,用以编辑脚本',
style: {
marginTop: '260px'
}
})
}"></div>
<j-monaco-editor language="javascript" style="height: 100%;" theme="vs" v-model:modelValue="editorValue" />
</div>
<div class="bottom">
<div style="width: 49.5%;">
<div class="bottom-title">
<div class="bottom-title-text">模拟输入</div>
<div class="bottom-title-topic">
<template v-if="instanceStore.current.transport === 'MQTT'">
<div style="margin-right: 5px;">Topic:</div>
<j-auto-complete placeholder="请输入Topic" style="width: 300px" :options="topicList"
:allowClear="true" :filterOption="filterOption" v-model:value="topic" />
</template>
<template v-else>
<div style="margin-right: 5px;">URL:</div>
<j-input placeholder="请输入URL" v-model:value="url" style="width: 300px"></j-input>
</template>
</div>
</div>
<j-textarea :rows="5" placeholder="// 二进制数据以0x开头的十六进制输入字符串数据输入原始字符串" style="margin-top: 10px;"
v-model:value="simulation" />
</div>
<div style="width: 49.5%;">
<div class="bottom-title">
<div class="bottom-title-text">运行结果</div>
</div>
<j-textarea :autoSize="{ minRows: 5 }" :style="resStyle" v-model:value="result" />
<div style="width: 49.5%">
<div class="bottom-title">
<div class="bottom-title-text">运行结果</div>
</div>
<j-textarea
:autoSize="{ minRows: 5 }"
:style="resStyle"
v-model:value="result"
/>
</div>
</div>
<div style="margin-top: 10px;margin-left: 10px;">
<PermissionButton type="primary" hasPermission="device/Instance:update" :loading="loading"
:disabled="isDisabled" @click="debug()" :tooltip="{
title: '需输入脚本和模拟数据后再点击',
}">
调试
</PermissionButton>
<PermissionButton hasPermission="device/Instance:update" :loading="loading" :disabled="!isTest" @click="save()"
:style="{ marginLeft: '10px' }" :tooltip="{
title: isTest ? '' : '请先调试',
}">
保存
</PermissionButton>
</div>
</j-card>
</div>
<div style="margin-top: 10px; margin-left: 10px">
<PermissionButton
type="primary"
hasPermission="device/Instance:update"
:loading="loading"
:disabled="isDisabled"
@click="debug()"
:tooltip="{
title: '需输入脚本和模拟数据后再点击',
}"
>
调试
</PermissionButton>
<PermissionButton
hasPermission="device/Instance:update"
:loading="loading"
:disabled="!isTest"
@click="save()"
:style="{ marginLeft: '10px' }"
:tooltip="{
title: isTest ? '' : '请先调试',
}"
>
保存
</PermissionButton>
</div>
</template>
<script setup lang='ts' name="Parsing">
import PermissionButton from '@/components/PermissionButton/index.vue'
import PermissionButton from '@/components/PermissionButton/index.vue';
// import MonacoEditor from '@/components/MonacoEditor/index.vue';
import { useFullscreen } from '@vueuse/core'
import { useFullscreen } from '@vueuse/core';
import { useInstanceStore } from '@/store/instance';
import {
deviceCode,
getProtocal,
testCode,
saveDeviceCode,
delDeviceCode
} from '@/api/device/instance'
delDeviceCode,
} from '@/api/device/instance';
import { message } from 'jetlinks-ui-components';
import { isBoolean } from 'lodash';
const defaultValue =
'//解码函数\r\nfunction decode(context) {\r\n //原始报文\r\n var buffer = context.payload();\r\n // 转为json\r\n // var json = context.json();\r\n //mqtt 时通过此方法获取topic\r\n // var topic = context.topic();\r\n\r\n // 提取变量\r\n // var topicVars = context.pathVars("/{deviceId}/**",topic)\r\n //温度属性\r\n var temperature = buffer.getShort(3) * 10;\r\n //湿度属性\r\n var humidity = buffer.getShort(6) * 10;\r\n return {\r\n "temperature": temperature,\r\n "humidity": humidity\r\n };\r\n}\r\n';
const el = ref<HTMLElement | null>(null)
const { toggle } = useFullscreen(el)
const el = ref<HTMLElement | null>(null);
const { toggle } = useFullscreen(el);
const instanceStore = useInstanceStore();
const topTitle = ref<string>('')
const readOnly = ref<boolean>(true)
const url = ref<string>('')
const topic = ref<string>('')
const topicList = ref([])
const simulation = ref<string>('')
const resultValue = ref<any>({})
const loading = ref<boolean>(false)
const isTest = ref<boolean>(false)
const editorValue = ref<string>('')
const topTitle = ref<string>('');
const readOnly = ref<boolean>(true);
const url = ref<string>('');
const topic = ref<string>('');
const topicList = ref([]);
const simulation = ref<string>('');
const resultValue = ref<any>({});
const loading = ref<boolean>(false);
const isTest = ref<boolean>(false);
const editorValue = ref<string>('');
const color = computed(() => ({
color: readOnly.value ? '#415ed1' : '#a6a6a6'
}))
const resStyle = computed(() => (isBoolean(resultValue.value.success) ? {
'margin-top': '10px',
'border-color': resultValue.value.success ? 'green' : 'red'
} : {
'margin-top': '10px',
}))
const filterOption = (inputValue: any, option: any) => option!.value.indexOf(inputValue) !== -1
color: readOnly.value ? '#415ed1' : '#a6a6a6',
}));
const resStyle = computed(() =>
isBoolean(resultValue.value.success)
? {
'margin-top': '10px',
'border-color': resultValue.value.success ? 'green' : 'red',
}
: {
'margin-top': '10px',
},
);
const filterOption = (inputValue: any, option: any) =>
option!.value.indexOf(inputValue) !== -1;
const isDisabled = computed(() => simulation.value === '')
const isDisabled = computed(() => simulation.value === '');
const result = computed(() => resultValue.value.success ? JSON.stringify(resultValue.value.outputs?.[0]) : resultValue.value.reason)
const result = computed(() =>
resultValue.value.success
? JSON.stringify(resultValue.value.outputs?.[0])
: resultValue.value.reason,
);
//
const rest = async () => {
const res = await delDeviceCode(instanceStore.current.productId, instanceStore.current.id)
const res = await delDeviceCode(
instanceStore.current.productId,
instanceStore.current.id,
);
if (res.status === 200) {
getDeviceCode();
message.success('操作成功')
message.success('操作成功');
}
};
//topic
const getTopic = async () => {
const res: any = await getProtocal(instanceStore.current.protocol, instanceStore.current.transport)
const res: any = await getProtocal(
instanceStore.current.protocol,
instanceStore.current.transport,
);
if (res.status === 200) {
const item = res.result.routes?.map((items: any) => ({
value: items.topic,
}));
// setTopicList(item);
topicList.value = item
topicList.value = item;
}
};
//
const getDeviceCode = async () => {
const res: any = await deviceCode(instanceStore.current.productId, instanceStore.current.id)
const res: any = await deviceCode(
instanceStore.current.productId,
instanceStore.current.id,
);
if (res.status === 200) {
const item = res.result?.configuration?.script ? res.result?.configuration?.script : defaultValue
const item = res.result?.configuration?.script
? res.result?.configuration?.script
: defaultValue;
if (res.result?.deviceId) {
readOnly.value = false
topTitle.value = 'rest'
editorValue.value = item
readOnly.value = false;
topTitle.value = 'rest';
editorValue.value = item;
} else {
readOnly.value = true
topTitle.value = 'edit'
editorValue.value = item
readOnly.value = true;
topTitle.value = 'edit';
editorValue.value = item;
}
}
}
};
//
const test = async (dataTest: any) => {
loading.value = true
const res = await testCode(dataTest)
loading.value = true;
const res = await testCode(dataTest);
if (res.status === 200) {
loading.value = false
resultValue.value = res?.result
loading.value = false;
resultValue.value = res?.result;
} else {
loading.value = false
loading.value = false;
}
};
@ -193,15 +268,18 @@ const save = async () => {
script: editorValue.value,
lang: 'javascript',
},
}
const res = await saveDeviceCode(instanceStore.current.productId, instanceStore.current.id, item)
};
const res = await saveDeviceCode(
instanceStore.current.productId,
instanceStore.current.id,
item,
);
if (res.status === 200) {
message.success('保存成功');
getDeviceCode();
}
};
const debug = () => {
if (instanceStore.current.transport === 'MQTT') {
if (topic.value !== '') {
@ -215,8 +293,8 @@ const debug = () => {
},
provider: 'jsr223',
payload: simulation.value,
})
isTest.value = true
});
isTest.value = true;
} else {
message.error('请输入topic');
}
@ -233,19 +311,17 @@ const debug = () => {
},
payload: simulation.value,
});
isTest.value = true
isTest.value = true;
} else {
message.error('请输入url');
}
}
}
};
onMounted(() => {
getDeviceCode()
getTopic()
})
getDeviceCode();
getTopic();
});
</script>
<style scoped lang='less'>

View File

@ -1,37 +1,31 @@
<template>
<j-card>
<div class="property-box">
<div class="property-box-left">
<j-input-search
v-model:value="value"
placeholder="请输入事件名称"
style="width: 200px; margin-bottom: 10px"
@search="onSearch"
:allowClear="true"
/>
<j-tabs
tab-position="left"
style="height: 600px"
v-if="tabList.length"
v-model:activeKey="activeKey"
:tabBarStyle="{ width: '200px' }"
@change="tabChange"
>
<j-tab-pane
v-for="i in tabList"
:key="i.key"
:tab="i.tab"
/>
</j-tabs>
<JEmpty v-else style="margin: 180px 0" />
</div>
<div class="property-box-right">
<Event v-if="type === 'event'" :data="data" />
<Property v-else-if="type === 'property'" :data="properties" />
<JEmpty v-else style="margin: 220px 0" />
</div>
<div class="property-box">
<div class="property-box-left">
<j-input-search
v-model:value="value"
placeholder="请输入事件名称"
style="width: 200px; margin-bottom: 10px"
@search="onSearch"
:allowClear="true"
/>
<j-tabs
tab-position="left"
style="height: 600px"
v-if="tabList.length"
v-model:activeKey="activeKey"
:tabBarStyle="{ width: '200px' }"
@change="tabChange"
>
<j-tab-pane v-for="i in tabList" :key="i.key" :tab="i.tab" />
</j-tabs>
<JEmpty v-else style="margin: 180px 0" />
</div>
</j-card>
<div class="property-box-right">
<Event v-if="type === 'event'" :data="data" />
<Property v-else-if="type === 'property'" :data="properties" />
<JEmpty v-else style="margin: 220px 0" />
</div>
</div>
</template>
<script lang="ts" setup>
@ -51,28 +45,32 @@ const tabList = ref<{ key: string; tab: string; type: 'property' | 'event' }[]>(
],
);
const type = ref<string>('property');
const data = ref<Record<string, any>>({})
const data = ref<Record<string, any>>({});
const value = ref<string>('');
const instanceStore = useInstanceStore()
const metadata = JSON.parse(instanceStore.current?.metadata || '{}')
const properties = metadata.properties
const events = metadata.events
const instanceStore = useInstanceStore();
const metadata = JSON.parse(instanceStore.current?.metadata || '{}');
const properties = metadata.properties;
const events = metadata.events;
watch(() => events, (newVal) => {
if(events && newVal.length){
newVal.map((item: any) => {
tabList.value.push({
...item,
key: item.id,
tab: item.name,
type: 'event',
})
})
}
}, {
deep: true,
immediate: true
})
watch(
() => events,
(newVal) => {
if (events && newVal.length) {
newVal.map((item: any) => {
tabList.value.push({
...item,
key: item.id,
tab: item.name,
type: 'event',
});
});
}
},
{
deep: true,
immediate: true,
},
);
const onSearch = () => {
const arr = [
@ -87,33 +85,32 @@ const onSearch = () => {
key: item.id,
tab: item.name,
type: 'event',
}
})
]
if(value.value){
};
}),
];
if (value.value) {
const li = arr.filter((i: any) => {
return i?.tab.indexOf(value.value) !== -1;
})
tabList.value = _.cloneDeep(li)
});
tabList.value = _.cloneDeep(li);
} else {
tabList.value = _.cloneDeep(arr)
tabList.value = _.cloneDeep(arr);
}
const dt = tabList.value?.[0]
const dt = tabList.value?.[0];
if (dt) {
data.value = dt
data.value = dt;
type.value = dt.type;
} else {
type.value = ''
type.value = '';
}
};
const tabChange = (key: string) => {
const dt = tabList.value.find((i) => i.key === key);
if (dt) {
data.value = dt
data.value = dt;
type.value = dt.type;
}
};
</script>
<style lang="less" scoped>

View File

@ -1,6 +1,6 @@
<template>
<j-spin :spinning="loading" v-if="metadata.properties.length">
<j-card>
<j-card :bordered="false" borderStyle="padding: 0">
<template #extra>
<j-space>
<j-button @click="visible = true">批量映射</j-button>
@ -107,7 +107,7 @@
:metaData="modelRef.dataSource"
/>
</j-spin>
<j-card v-else>
<j-card v-else :bordered="false" borderStyle="padding: 0">
<JEmpty description='暂无数据,请配置物模型' style="margin: 10% 0" />
</j-card>
</template>

View File

@ -8,7 +8,9 @@
<template #title>
<div style="display: flex; align-items: center">
<j-tooltip :title="instanceStore.current?.name">
<div class="deviceDetailHead">{{ instanceStore.current?.name }}</div>
<div class="deviceDetailHead">
{{ instanceStore.current?.name }}
</div>
</j-tooltip>
<j-divider type="vertical" />
<j-space>
@ -95,11 +97,15 @@
style="margin-right: 20px; cursor: pointer"
/>
</template>
<component
:is="tabs[instanceStore.tabActiveKey]"
v-bind="{ type: 'device' }"
@onJump="onTabChange"
/>
<FullPage>
<j-card :bordered="false">
<component
:is="tabs[instanceStore.tabActiveKey]"
v-bind="{ type: 'device' }"
@onJump="onTabChange"
/>
</j-card>
</FullPage>
</page-container>
</template>
@ -121,12 +127,12 @@ import { message } from 'jetlinks-ui-components';
import { getImage } from '@/utils/comm';
import { getWebSocket } from '@/utils/websocket';
import { useMenuStore } from '@/store/menu';
import {useRouterParams} from "@/utils/hooks/useParams";
import { useRouterParams } from '@/utils/hooks/useParams';
const menuStory = useMenuStore();
const route = useRoute();
const routerParams = useRouterParams()
const routerParams = useRouterParams();
const instanceStore = useInstanceStore();
const statusMap = new Map();
@ -266,18 +272,18 @@ const getDetail = () => {
// );
const getDetailFn = async () => {
const _id = route.params?.id
if (_id) {
await instanceStore.refresh(String(_id));
getStatus(String(_id));
list.value = [...initList];
getDetail();
}
instanceStore.tabActiveKey = routerParams.params.value.tab || 'Info';
}
const _id = route.params?.id;
if (_id) {
await instanceStore.refresh(String(_id));
getStatus(String(_id));
list.value = [...initList];
getDetail();
}
instanceStore.tabActiveKey = routerParams.params.value.tab || 'Info';
};
onMounted(() => {
getDetailFn()
getDetailFn();
});
const onBack = () => {

View File

@ -5,37 +5,42 @@
target="device-instance"
@search="handleSearch"
/>
<JProTable
ref="instanceRef"
:columns="columns"
:request="query"
:defaultParams="{ sorts: [{ name: 'createTime', order: 'desc' }] }"
:rowSelection="
isCheck
? {
selectedRowKeys: _selectedRowKeys,
onChange: onSelectChange,
}
: false
"
:params="params"
>
<template #headerTitle>
<j-space>
<PermissionButton
type="primary"
@click="handleAdd"
hasPermission="device/Instance:add"
>
<template #icon><AIcon type="PlusOutlined" /></template>
新增
</PermissionButton>
<BatchDropdown
v-model:isCheck="isCheck"
:actions="batchActions"
@change="onCheckChange"
/>
<!-- <j-dropdown>
<FullPage>
<JProTable
ref="instanceRef"
:columns="columns"
:request="query"
:defaultParams="{
sorts: [{ name: 'createTime', order: 'desc' }],
}"
:rowSelection="
isCheck
? {
selectedRowKeys: _selectedRowKeys,
onChange: onSelectChange,
}
: false
"
:params="params"
>
<template #headerTitle>
<j-space>
<PermissionButton
type="primary"
@click="handleAdd"
hasPermission="device/Instance:add"
>
<template #icon
><AIcon type="PlusOutlined"
/></template>
新增
</PermissionButton>
<BatchDropdown
v-model:isCheck="isCheck"
:actions="batchActions"
@change="onCheckChange"
/>
<!-- <j-dropdown>
<j-button
>批量操作 <AIcon type="DownOutlined"
/></j-button>
@ -141,116 +146,125 @@
</j-menu>
</template>
</j-dropdown> -->
</j-space>
</template>
<template #card="slotProps">
<CardBox
:value="slotProps"
@click="handleClick"
:actions="getActions(slotProps, 'card')"
:active="_selectedRowKeys.includes(slotProps.id)"
:status="slotProps.state?.value"
:statusText="slotProps.state?.text"
:statusNames="{
online: 'processing',
offline: 'error',
notActive: 'warning',
}"
>
<template #img>
<img
:src="getImage('/device/instance/device-card.png')"
/>
</template>
<template #content>
<Ellipsis style="width: calc(100% - 100px)">
<span style="font-size: 16px; font-weight: 600">
{{ slotProps.name }}
</span>
</Ellipsis>
<j-row style="margin-top: 20px">
<j-col :span="12">
<div class="card-item-content-text">
设备类型
</div>
<div>{{ slotProps.deviceType?.text }}</div>
</j-col>
<j-col :span="12">
<div class="card-item-content-text">
产品名称
</div>
<Ellipsis style="width: 100%">
{{ slotProps.productName }}
</Ellipsis>
</j-col>
</j-row>
</template>
<template #actions="item">
<PermissionButton
:disabled="item.disabled"
:popConfirm="item.popConfirm"
:tooltip="{
...item.tooltip,
}"
@click="item.onClick"
:hasPermission="'device/Instance:' + 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 #state="slotProps">
<BadgeStatus
:status="slotProps.state?.value"
:text="slotProps.state?.text"
:statusNames="{
online: 'processing',
offline: 'error',
notActive: 'warning',
}"
/>
</template>
<template #createTime="slotProps">
<span>{{
slotProps?.createTime ? dayjs(slotProps.createTime).format('YYYY-MM-DD HH:mm:ss') : ''
}}</span>
</template>
<template #action="slotProps">
<j-space>
<template
v-for="i in getActions(slotProps, 'table')"
:key="i.key"
</j-space>
</template>
<template #card="slotProps">
<CardBox
:value="slotProps"
@click="handleClick"
:actions="getActions(slotProps, 'card')"
:active="_selectedRowKeys.includes(slotProps.id)"
:status="slotProps.state?.value"
:statusText="slotProps.state?.text"
:statusNames="{
online: 'processing',
offline: 'error',
notActive: 'warning',
}"
>
<PermissionButton
:disabled="i.disabled"
:popConfirm="i.popConfirm"
:tooltip="{
...i.tooltip,
}"
@click="i.onClick"
type="link"
style="padding: 0 5px"
:danger="i.key === 'delete'"
:hasPermission="
i.key === 'view'
? true
: 'device/Instance:' + i.key
"
<template #img>
<img
:src="
getImage('/device/instance/device-card.png')
"
/>
</template>
<template #content>
<Ellipsis style="width: calc(100% - 100px)">
<span style="font-size: 16px; font-weight: 600">
{{ slotProps.name }}
</span>
</Ellipsis>
<j-row style="margin-top: 20px">
<j-col :span="12">
<div class="card-item-content-text">
设备类型
</div>
<div>{{ slotProps.deviceType?.text }}</div>
</j-col>
<j-col :span="12">
<div class="card-item-content-text">
产品名称
</div>
<Ellipsis style="width: 100%">
{{ slotProps.productName }}
</Ellipsis>
</j-col>
</j-row>
</template>
<template #actions="item">
<PermissionButton
:disabled="item.disabled"
:popConfirm="item.popConfirm"
:tooltip="{
...item.tooltip,
}"
@click="item.onClick"
:hasPermission="'device/Instance:' + 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 #state="slotProps">
<BadgeStatus
:status="slotProps.state?.value"
:text="slotProps.state?.text"
:statusNames="{
online: 'processing',
offline: 'error',
notActive: 'warning',
}"
/>
</template>
<template #createTime="slotProps">
<span>{{
slotProps?.createTime
? dayjs(slotProps.createTime).format(
'YYYY-MM-DD HH:mm:ss',
)
: ''
}}</span>
</template>
<template #action="slotProps">
<j-space>
<template
v-for="i in getActions(slotProps, 'table')"
:key="i.key"
>
<template #icon><AIcon :type="i.icon" /></template>
</PermissionButton>
</template>
</j-space>
</template>
</JProTable>
<PermissionButton
:disabled="i.disabled"
:popConfirm="i.popConfirm"
:tooltip="{
...i.tooltip,
}"
@click="i.onClick"
type="link"
style="padding: 0 5px"
:danger="i.key === 'delete'"
:hasPermission="
i.key === 'view'
? true
: 'device/Instance:' + i.key
"
>
<template #icon
><AIcon :type="i.icon"
/></template>
</PermissionButton>
</template>
</j-space>
</template>
</JProTable>
</FullPage>
</page-container>
<Import
v-if="importVisible"
@ -867,7 +881,7 @@ const handleSearch = (_params: any) => {
) {
return {
...item2,
column: 'productId$product-info'
column: 'productId$product-info',
};
}
return item2;

View File

@ -5,147 +5,166 @@
target="edge-device"
@search="handleSearch"
/>
<JProTable
ref="edgeDeviceRef"
:columns="columns"
:request="query"
:defaultParams="defaultParams"
:params="params"
:gridColumn="3"
>
<template #headerTitle>
<j-space>
<PermissionButton
type="primary"
@click="handleAdd"
hasPermission="edge/Device:add"
>
<template #icon><AIcon type="PlusOutlined" /></template>
新增
</PermissionButton>
<PermissionButton
@click="importVisible = true"
hasPermission="edge/Device:import"
>
<template #icon
><AIcon type="ImportOutlined"
/></template>
导入
</PermissionButton>
</j-space>
</template>
<template #card="slotProps">
<CardBox
:value="slotProps"
:actions="getActions(slotProps, 'card')"
:status="slotProps.state?.value"
:statusText="slotProps.state?.text"
:statusNames="{
online: 'processing',
offline: 'error',
notActive: 'warning',
}"
>
<template #img>
<img
:src="getImage('/device/instance/device-card.png')"
/>
</template>
<template #content>
<Ellipsis style="width: calc(100% - 100px)">
<span
style="font-size: 16px; font-weight: 600"
@click.stop="handleView(slotProps.id)"
>
{{ slotProps.name }}
</span>
</Ellipsis>
<j-row style="margin-top: 20px">
<j-col :span="12">
<div class="card-item-content-text">
设备类型
</div>
<div>{{ slotProps.deviceType?.text }}</div>
</j-col>
<j-col :span="12">
<div class="card-item-content-text">
产品名称
</div>
<Ellipsis style="width: 100%">
{{ slotProps.productName }}
</Ellipsis>
</j-col>
</j-row>
</template>
<template #actions="item">
<FullPage>
<JProTable
ref="edgeDeviceRef"
:columns="columns"
:request="query"
:defaultParams="defaultParams"
:params="params"
:gridColumn="3"
>
<template #headerTitle>
<j-space>
<PermissionButton
:disabled="item.disabled"
:popConfirm="item.popConfirm"
:tooltip="{
...item.tooltip,
}"
@click="item.onClick"
:hasPermission="'edge/Device:' + item.key"
type="primary"
@click="handleAdd"
hasPermission="edge/Device:add"
>
<AIcon
type="DeleteOutlined"
v-if="item.key === 'delete'"
<template #icon
><AIcon type="PlusOutlined"
/></template>
新增
</PermissionButton>
<PermissionButton
@click="importVisible = true"
hasPermission="edge/Device:import"
>
<template #icon
><AIcon type="ImportOutlined"
/></template>
导入
</PermissionButton>
</j-space>
</template>
<template #card="slotProps">
<CardBox
:value="slotProps"
:actions="getActions(slotProps, 'card')"
:status="slotProps.state?.value"
:statusText="slotProps.state?.text"
:statusNames="{
online: 'processing',
offline: 'error',
notActive: 'warning',
}"
>
<template #img>
<img
:src="
getImage('/device/instance/device-card.png')
"
/>
<template v-else>
<AIcon :type="item.icon" />
<span>{{ item?.text }}</span>
</template>
</PermissionButton>
</template>
</CardBox>
</template>
<template #state="slotProps">
<BadgeStatus
:status="slotProps.state?.value"
:text="slotProps.state?.text"
:statusNames="{
online: 'processing',
offline: 'error',
notActive: 'warning',
}"
/>
</template>
<template #registryTime="slotProps">
<span>{{
dayjs(slotProps.registryTime).format('YYYY-MM-DD HH:mm:ss')
}}</span>
</template>
<template #action="slotProps">
<j-space>
<template
v-for="i in getActions(slotProps, 'table')"
:key="i.key"
>
<PermissionButton
:disabled="i.disabled"
:popConfirm="i.popConfirm"
:tooltip="{
...i.tooltip,
}"
@click="i.onClick"
type="link"
style="padding: 0 5px"
:danger="i.key === 'delete'"
:hasPermission="i.key === 'view' ? true : 'edge/Device:' + i.key"
</template>
<template #content>
<Ellipsis style="width: calc(100% - 100px)">
<span
style="font-size: 16px; font-weight: 600"
@click.stop="handleView(slotProps.id)"
>
{{ slotProps.name }}
</span>
</Ellipsis>
<j-row style="margin-top: 20px">
<j-col :span="12">
<div class="card-item-content-text">
设备类型
</div>
<div>{{ slotProps.deviceType?.text }}</div>
</j-col>
<j-col :span="12">
<div class="card-item-content-text">
产品名称
</div>
<Ellipsis style="width: 100%">
{{ slotProps.productName }}
</Ellipsis>
</j-col>
</j-row>
</template>
<template #actions="item">
<PermissionButton
:disabled="item.disabled"
:popConfirm="item.popConfirm"
:tooltip="{
...item.tooltip,
}"
@click="item.onClick"
:hasPermission="'edge/Device:' + 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 #state="slotProps">
<BadgeStatus
:status="slotProps.state?.value"
:text="slotProps.state?.text"
:statusNames="{
online: 'processing',
offline: 'error',
notActive: 'warning',
}"
/>
</template>
<template #registryTime="slotProps">
<span>{{
dayjs(slotProps.registryTime).format(
'YYYY-MM-DD HH:mm:ss',
)
}}</span>
</template>
<template #action="slotProps">
<j-space>
<template
v-for="i in getActions(slotProps, 'table')"
:key="i.key"
>
<template #icon><AIcon :type="i.icon" /></template>
</PermissionButton>
</template>
</j-space>
</template>
</JProTable>
<PermissionButton
:disabled="i.disabled"
:popConfirm="i.popConfirm"
:tooltip="{
...i.tooltip,
}"
@click="i.onClick"
type="link"
style="padding: 0 5px"
:danger="i.key === 'delete'"
:hasPermission="
i.key === 'view'
? true
: 'edge/Device:' + i.key
"
>
<template #icon
><AIcon :type="i.icon"
/></template>
</PermissionButton>
</template>
</j-space>
</template>
</JProTable>
</FullPage>
<Save
v-if="visible"
:data="current"
@close="visible = false"
@save="saveBtn"
/>
<Import @save="onRefresh" @close="importVisible = false" v-if="importVisible" type="official-edge-gateway" />
<Import
@save="onRefresh"
@close="importVisible = false"
v-if="importVisible"
type="official-edge-gateway"
/>
</page-container>
</template>
@ -192,18 +211,18 @@ const visible = ref<boolean>(false);
const current = ref<Record<string, any>>({});
const transformData = (arr: any[]): any[] => {
if(Array.isArray(arr) && arr.length){
if (Array.isArray(arr) && arr.length) {
return (arr || []).map((item: any) => {
return {
...item,
id: `classifiedId is ${item.id}`,
children: transformData(item.children)
}
})
children: transformData(item.children),
};
});
} else {
return []
return [];
}
}
};
const columns = [
{
@ -471,9 +490,9 @@ const saveBtn = () => {
};
const onRefresh = () => {
importVisible.value = false
importVisible.value = false;
edgeDeviceRef.value?.reload();
}
};
</script>
<style lang="less" scoped>

View File

@ -5,131 +5,141 @@
target="edge-resource"
@search="handleSearch"
/>
<JProTable
ref="edgeResourceRef"
:columns="columns"
:request="query"
:defaultParams="defaultParams"
:params="params"
>
<template #card="slotProps">
<CardBox
:value="slotProps"
@click="handleView(slotProps)"
:actions="getActions(slotProps, 'card')"
:status="slotProps.state?.value"
:statusText="slotProps.state?.text"
:statusNames="{
enabled: 'processing',
disabled: 'error',
}"
>
<template #img>
<img
:src="getImage('/device/instance/device-card.png')"
/>
</template>
<template #content>
<Ellipsis style="width: calc(100% - 100px)">
<span style="font-size: 16px; font-weight: 600">
{{ slotProps.name }}
</span>
</Ellipsis>
<j-row style="margin-top: 20px">
<j-col :span="12">
<div class="card-item-content-text">
通讯协议
</div>
<Ellipsis>{{
options.find(
(i) => i.value === slotProps.category,
)?.label || slotProps.category
}}</Ellipsis>
</j-col>
<j-col :span="12">
<div class="card-item-content-text">
所属边缘网关
</div>
<Ellipsis style="width: 100%">
{{ slotProps.sourceName }}
</Ellipsis>
</j-col>
</j-row>
</template>
<template #actions="item">
<PermissionButton
:disabled="item.disabled"
:popConfirm="item.popConfirm"
:tooltip="{
...item.tooltip,
}"
@click="item.onClick"
:hasPermission="'edge/Resource:' + 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 #state="slotProps">
<BadgeStatus
:status="slotProps.state?.value"
:text="slotProps.state?.text"
:statusNames="{
enabled: 'processing',
disabled: 'error',
}"
/>
</template>
<template #sourceId="slotProps">
{{ slotProps.sourceName }}
</template>
<template #category="slotProps">
{{
options.find((i) => i.value === slotProps.category)
?.label || slotProps.category
}}
</template>
<template #createTime="slotProps">
<span>{{
dayjs(slotProps.createTime).format('YYYY-MM-DD HH:mm:ss')
}}</span>
</template>
<template #action="slotProps">
<j-space>
<template
v-for="i in getActions(slotProps, 'table')"
:key="i.key"
<FullPage>
<JProTable
ref="edgeResourceRef"
:columns="columns"
:request="query"
:defaultParams="defaultParams"
:params="params"
>
<template #card="slotProps">
<CardBox
:value="slotProps"
@click="handleView(slotProps)"
:actions="getActions(slotProps, 'card')"
:status="slotProps.state?.value"
:statusText="slotProps.state?.text"
:statusNames="{
enabled: 'processing',
disabled: 'error',
}"
>
<PermissionButton
:disabled="i.disabled"
:popConfirm="i.popConfirm"
:tooltip="{
...i.tooltip,
}"
@click="i.onClick"
type="link"
style="padding: 0 5px"
:danger="i.key === 'delete'"
:hasPermission="
i.key === 'view'
? true
: 'edge/Resource:' + i.key
"
<template #img>
<img
:src="
getImage('/device/instance/device-card.png')
"
/>
</template>
<template #content>
<Ellipsis style="width: calc(100% - 100px)">
<span style="font-size: 16px; font-weight: 600">
{{ slotProps.name }}
</span>
</Ellipsis>
<j-row style="margin-top: 20px">
<j-col :span="12">
<div class="card-item-content-text">
通讯协议
</div>
<Ellipsis>{{
options.find(
(i) =>
i.value === slotProps.category,
)?.label || slotProps.category
}}</Ellipsis>
</j-col>
<j-col :span="12">
<div class="card-item-content-text">
所属边缘网关
</div>
<Ellipsis style="width: 100%">
{{ slotProps.sourceName }}
</Ellipsis>
</j-col>
</j-row>
</template>
<template #actions="item">
<PermissionButton
:disabled="item.disabled"
:popConfirm="item.popConfirm"
:tooltip="{
...item.tooltip,
}"
@click="item.onClick"
:hasPermission="'edge/Resource:' + 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 #state="slotProps">
<BadgeStatus
:status="slotProps.state?.value"
:text="slotProps.state?.text"
:statusNames="{
enabled: 'processing',
disabled: 'error',
}"
/>
</template>
<template #sourceId="slotProps">
{{ slotProps.sourceName }}
</template>
<template #category="slotProps">
{{
options.find((i) => i.value === slotProps.category)
?.label || slotProps.category
}}
</template>
<template #createTime="slotProps">
<span>{{
dayjs(slotProps.createTime).format(
'YYYY-MM-DD HH:mm:ss',
)
}}</span>
</template>
<template #action="slotProps">
<j-space>
<template
v-for="i in getActions(slotProps, 'table')"
:key="i.key"
>
<template #icon><AIcon :type="i.icon" /></template>
</PermissionButton>
</template>
</j-space>
</template>
</JProTable>
<PermissionButton
:disabled="i.disabled"
:popConfirm="i.popConfirm"
:tooltip="{
...i.tooltip,
}"
@click="i.onClick"
type="link"
style="padding: 0 5px"
:danger="i.key === 'delete'"
:hasPermission="
i.key === 'view'
? true
: 'edge/Resource:' + i.key
"
>
<template #icon
><AIcon :type="i.icon"
/></template>
</PermissionButton>
</template>
</j-space>
</template>
</JProTable>
</FullPage>
<Save
v-if="visible"
:data="current"

View File

@ -278,7 +278,7 @@ watch(
}
}
},
{ immediate: true, deep: true },
{ immediate: true },
);
watch(

View File

@ -154,7 +154,7 @@ const TypeList = [
},
{
label: '按变量',
value: 'variable',
value: 'context',
image: getImage('/scene/device-variable.png'),
tip: '选择设备ID为上游变量值的设备',
},
@ -236,7 +236,7 @@ const filterType = async (newVal: any) => {
!props.parallel &&
props.name !== 0
) {
const array = TypeList.filter((item) => item.value === 'variable');
const array = TypeList.filter((item) => item.value === 'context');
_list.push(...array);
}
list.value = _list;
@ -246,7 +246,7 @@ const filterType = async (newVal: any) => {
!props.parallel &&
props.name !== 0
) {
const array = TypeList.filter((item) => item.value === 'variable');
const array = TypeList.filter((item) => item.value === 'context');
_list.push(...array);
}
list.value = _list;
@ -287,7 +287,12 @@ const onTagChange = (val: any[], arr: any[]) => {
modelRef.source = 'fixed';
}
const tagName = arr.map((i, _index) => {
const _type = (_index !== 0 && _index !== (arr || []).length && i.type) ? (i.type === 'and' ? '并且' : '或者') : '';
const _type =
_index !== 0 && _index !== (arr || []).length && i.type
? i.type === 'and'
? '并且'
: '或者'
: '';
return `${_type}${i.name}${i.value}`;
});
emits('save', unref(modelRef), { tagName: tagName.join('') });
@ -295,6 +300,8 @@ const onTagChange = (val: any[], arr: any[]) => {
const onVariableChange = (val: any, node: any) => {
modelRef.deviceId = val;
modelRef.source = 'upper';
modelRef.upperKey = val;
modelRef.selectorValues = [{ value: val, name: node.description }] as any;
emits('save', unref(modelRef), { name: node.description });
};
@ -333,7 +340,7 @@ watch(
return item.children.find((i: any) => i.id === param);
});
if (isVariable) {
modelRef.selector = 'variable';
modelRef.selector = 'context';
}
}
},

View File

@ -181,6 +181,7 @@ const onProductChange = (_val: any, bol: boolean) => {
JSON.parse(_val.metadata || '{}'),
DeviceModel?.message,
);
console.log(flag)
if (!flag) {
DeviceModel.message = {
messageType: 'INVOKE_FUNCTION',