fix: bug#11226 样式铺满

This commit is contained in:
leiqiaochu 2023-03-30 17:07:33 +08:00
parent 881cc39e9b
commit e98f168b20
15 changed files with 1393 additions and 1273 deletions

View File

@ -6,61 +6,65 @@
target="category"
@search="handleSearch"
/>
<JProTable
ref="tableRef"
:columns="table.columns"
:request="queryTree"
model="TABLE"
type="TREE"
v-model:expandedRowKeys="expandedRowKeys"
:scroll="{ y: 550 }"
:defaultParams="{
paging: false,
sorts: [
{ name: 'sortIndex', order: 'asc' },
{
name: 'createTime',
order: 'desc',
},
],
}"
:params="params"
:loading="tableLoading"
>
<template #headerTitle>
<PermissionButton
type="primary"
@click="add"
hasPermission="device/Category:add"
>
<template #icon><AIcon type="PlusOutlined" /></template>
新增
</PermissionButton>
</template>
<template #action="slotProps">
<j-space>
<template
v-for="i in getActions(slotProps, 'table')"
:key="i.key"
<FullPage>
<JProTable
ref="tableRef"
:columns="table.columns"
:request="queryTree"
model="TABLE"
type="TREE"
v-model:expandedRowKeys="expandedRowKeys"
:scroll="{ y: 550 }"
:defaultParams="{
paging: false,
sorts: [
{ name: 'sortIndex', order: 'asc' },
{
name: 'createTime',
order: 'desc',
},
],
}"
:params="params"
:loading="tableLoading"
>
<template #headerTitle>
<PermissionButton
type="primary"
@click="add"
hasPermission="device/Category:add"
>
<PermissionButton
:disabled="i.disabled"
:popConfirm="i.popConfirm"
:hasPermission="'device/Category:' + i.key"
:tooltip="{
...i.tooltip,
}"
@click="i.onClick"
type="link"
style="padding: 0px"
:danger="i.key === 'delete'"
<template #icon><AIcon type="PlusOutlined" /></template>
新增
</PermissionButton>
</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"
:hasPermission="'device/Category:' + i.key"
:tooltip="{
...i.tooltip,
}"
@click="i.onClick"
type="link"
style="padding: 0px"
:danger="i.key === 'delete'"
>
<template #icon
><AIcon :type="i.icon"
/></template>
</PermissionButton>
</template>
</j-space>
</template>
</JProTable>
</FullPage>
<!-- 新增和编辑弹窗 -->
<ModifyModal
ref="modifyRef"

View File

@ -1,56 +1,51 @@
<!-- 配置信息 -->
<template>
<j-card style="min-height: 100%">
<j-descriptions bordered>
<template #title>
<div style="display: flex">
<h3>配置信息</h3>
<!-- <div style="margin: 0 0px 0 15px; color: #1d39c4">
<j-descriptions bordered>
<template #title>
<div style="display: flex">
<h3>配置信息</h3>
<!-- <div style="margin: 0 0px 0 15px; color: #1d39c4">
<AIcon type="EditOutlined" @click="editConfig" />
</div> -->
<PermissionButton
type="link"
@click="editConfig"
hasPermission="device/Product:update"
>
<template #icon><AIcon type="EditOutlined" /></template>
</PermissionButton>
</div>
</template>
<PermissionButton
type="link"
@click="editConfig"
hasPermission="device/Product:update"
>
<template #icon><AIcon type="EditOutlined" /></template>
</PermissionButton>
</div>
</template>
<j-descriptions-item label="ID">
<Ellipsis>{{ productStore.current.id }}</Ellipsis>
</j-descriptions-item>
<j-descriptions-item label="产品分类">
<Ellipsis>{{ productStore.current.classifiedName }}</Ellipsis>
</j-descriptions-item>
<j-descriptions-item label="设备类型">{{
productStore.current.deviceType?.text
}}</j-descriptions-item>
<j-descriptions-item label="ID">
<Ellipsis>{{ productStore.current.id }}</Ellipsis>
</j-descriptions-item>
<j-descriptions-item label="产品分类">
<Ellipsis>{{ productStore.current.classifiedName }}</Ellipsis>
</j-descriptions-item>
<j-descriptions-item label="设备类型">{{
productStore.current.deviceType?.text
}}</j-descriptions-item>
<j-descriptions-item label="接入方式">
<j-button type="link" @click="changeTables">{{
productStore.current.accessName
? productStore.current.accessName
: '配置接入方式'
}}</j-button>
</j-descriptions-item>
<j-descriptions-item label="创建时间">{{
dayjs(productStore.current.createTime).format(
'YYYY-MM-DD HH:mm:ss',
)
}}</j-descriptions-item>
<j-descriptions-item label="更新时间">{{
dayjs(productStore.current.modifyTime).format(
'YYYY-MM-DD HH:mm:ss',
)
}}</j-descriptions-item>
<j-descriptions-item label="接入方式">
<j-button type="link" @click="changeTables">{{
productStore.current.accessName
? productStore.current.accessName
: '配置接入方式'
}}</j-button>
</j-descriptions-item>
<j-descriptions-item label="创建时间">{{
dayjs(productStore.current.createTime).format('YYYY-MM-DD HH:mm:ss')
}}</j-descriptions-item>
<j-descriptions-item label="更新时间">{{
dayjs(productStore.current.modifyTime).format('YYYY-MM-DD HH:mm:ss')
}}</j-descriptions-item>
<j-descriptions-item label="说明" :span="3">
{{ productStore.current.describe }}
</j-descriptions-item>
</j-descriptions>
<j-descriptions-item label="说明" :span="3">
{{ productStore.current.describe }}
</j-descriptions-item>
</j-descriptions>
</j-card>
<!-- 编辑 -->
<Save ref="saveRef" :isAdd="isAdd" :title="title" @success="refresh" />
</template>

View File

@ -1,138 +1,193 @@
<template>
<j-card>
<div>
<div class="top">
<div>
脚本语言:
<j-select :defaultValue="'JavaScript'" style="width: 200;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">
<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="productStore.current.transportProtocol === 'MQTT'">
<div style="margin-right: 5px;">Topic:</div>
<j-auto-complete placeholder="请输入Topic" style="width: 300px" :options="topicList"
:allowClear="true" :filterOption="(inputValue: any, option: any) =>
option!.value.indexOf(inputValue) !== -1" 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>
<div>
<div class="top">
<div>
脚本语言:
<j-select
:defaultValue="'JavaScript'"
style="width: 200; 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 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 class="edit" ref="el">
<j-monaco-editor
language="javascript"
style="height: 100%"
theme="vs"
v-model:modelValue="editorValue"
/>
</div>
</j-card>
<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="
productStore.current.transportProtocol ===
'MQTT'
"
>
<div style="margin-right: 5px">Topic:</div>
<j-auto-complete
placeholder="请输入Topic"
style="width: 300px"
:options="topicList"
:allowClear="true"
:filterOption="(inputValue: any, option: any) =>
option!.value.indexOf(inputValue) !== -1"
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>
</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>
</template>
<script setup lang='ts' name="DataAnalysis">
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 { useProductStore } from '@/store/product';
import {
productCode,
getProtocal,
testCode,
saveProductCode,
} from '@/api/device/instance'
} 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 productStore = useProductStore()
const el = ref<HTMLElement | null>(null);
const { toggle } = useFullscreen(el);
const productStore = useProductStore();
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 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 resStyle = computed(() =>
isBoolean(resultValue.value.success)
? {
'margin-top': '10px',
'border-color': resultValue.value.success ? 'green' : 'red',
}
: {
'margin-top': '10px',
},
);
const resStyle = computed(() => (isBoolean(resultValue.value.success) ? {
'margin-top': '10px',
'border-color': resultValue.value.success ? 'green' : 'red'
} : {
'margin-top': '10px',
}))
const isDisabled = computed(() => simulation.value === '')
const result = computed(() => resultValue.value.success ? JSON.stringify(resultValue.value.outputs?.[0]) : resultValue.value.reason)
const isDisabled = computed(() => simulation.value === '');
const result = computed(() =>
resultValue.value.success
? JSON.stringify(resultValue.value.outputs?.[0])
: resultValue.value.reason,
);
//topic
const getTopic = async () => {
const res: any = await getProtocal(productStore.current.messageProtocol, productStore.current.transportProtocol)
const res: any = await getProtocal(
productStore.current.messageProtocol,
productStore.current.transportProtocol,
);
if (res.status === 200) {
const item = res.result.routes?.map((items: any) => ({
value: items.topic,
}));
topicList.value = item
topicList.value = item;
}
};
//
const getProductCode = async () => {
const res: any = await productCode(productStore.current.id)
const res: any = await productCode(productStore.current.id);
if (res.status === 200) {
if(res.result){
editorValue.value = res.result?.configuration?.script
}else{
editorValue.value = defaultValue
if (res.result) {
editorValue.value = res.result?.configuration?.script;
} else {
editorValue.value = defaultValue;
}
}
}
};
//
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;
}
};
@ -144,15 +199,14 @@ const save = async () => {
script: editorValue.value,
lang: 'javascript',
},
}
const res = await saveProductCode(productStore.current.id, item)
};
const res = await saveProductCode(productStore.current.id, item);
if (res.status === 200) {
message.success('保存成功');
getProductCode();
}
};
const debug = () => {
if (productStore.current.transportProtocol === 'MQTT') {
if (topic.value !== '') {
@ -166,8 +220,8 @@ const debug = () => {
},
provider: 'jsr223',
payload: simulation.value,
})
isTest.value = true
});
isTest.value = true;
} else {
message.error('请输入topic');
}
@ -184,19 +238,17 @@ const debug = () => {
},
payload: simulation.value,
});
isTest.value = true
isTest.value = true;
} else {
message.error('请输入url');
}
}
}
};
onMounted(() => {
getProductCode()
getTopic()
})
getProductCode();
getTopic();
});
</script>
<style scoped lang='less'>

View File

@ -1,30 +1,26 @@
<!-- 设备接入 -->
<template>
<j-card style="min-height: 100%">
<div v-if="productStore.current.accessId === undefined || null">
<j-empty :image="simpleImage">
<template #description>
<span
v-if="
permissionStore.hasPermission(
'device/Product:update',
)
"
>
请先<j-button type="link" @click="showModal"
>选择</j-button
>设备接入网关用以提供设备接入能力
</span>
<span v-else>请联系管理员配置产品接入方式</span>
</template>
</j-empty>
</div>
<div v-else>
<j-row :gutter="24">
<j-col :span="12">
<Title data="接入方式">
<template #extra>
<!-- <j-tooltip
<div v-if="productStore.current.accessId === undefined || null">
<j-empty :image="simpleImage">
<template #description>
<span
v-if="
permissionStore.hasPermission('device/Product:update')
"
>
请先<j-button type="link" @click="showModal">选择</j-button
>设备接入网关用以提供设备接入能力
</span>
<span v-else>请联系管理员配置产品接入方式</span>
</template>
</j-empty>
</div>
<div v-else>
<j-row :gutter="24">
<j-col :span="12">
<Title data="接入方式">
<template #extra>
<!-- <j-tooltip
:title="
productStore.current?.count &&
productStore.current?.count > 0
@ -45,249 +41,229 @@
>更换</j-button
>
</j-tooltip> -->
<PermissionButton
style="margin: 0 0 0 20px"
type="primary"
size="small"
:tooltip="{
title:
productStore.current?.count &&
productStore.current?.count > 0
? '产品下有设备实例时不能更换接入方式'
: '',
}"
:disabled="
<PermissionButton
style="margin: 0 0 0 20px"
type="primary"
size="small"
:tooltip="{
title:
productStore.current?.count &&
productStore.current?.count > 0
"
ghost
@click="showDevice"
hasPermission="device/Product:update"
>
更换
</PermissionButton>
</template>
</Title>
? '产品下有设备实例时不能更换接入方式'
: '',
}"
:disabled="
productStore.current?.count &&
productStore.current?.count > 0
"
ghost
@click="showDevice"
hasPermission="device/Product:update"
>
更换
</PermissionButton>
</template>
</Title>
<div>
<div>
<div>
{{ access?.name }}
{{ access?.name }}
</div>
<div>
{{
access?.description ||
dataSource.find(
(item) => item?.id === access?.provider,
)?.description
}}
</div>
</div>
<div class="item-style">
<Title data="消息协议"></Title>
<div>
{{ access?.protocolDetail?.name }}
</div>
<!-- 显示md文件内容 -->
<div v-if="config?.document" v-html="markdownToHtml"></div>
</div>
<div class="item-style">
<Title data="连接信息"></Title>
<div v-if="access?.channelInfo?.addresses.length > 0">
<div
v-for="item in access?.channelInfo?.addresses"
:key="item.address"
>
<j-badge
:color="item.health === -1 ? 'red' : 'green'"
:text="item.address"
>
</j-badge>
</div>
<div>
</div>
<div v-else>{{ '暂无连接信息' }}</div>
</div>
<Title
v-if="metadata?.name"
:data="metadata?.name"
class="config"
>
<template #extra>
<j-tooltip title="此配置来自于产品接入方式所选择的协议">
<AIcon
type="QuestionCircleOutlined"
style="margin-left: 2px"
/>
</j-tooltip>
</template>
</Title>
<j-form ref="formRef" :model="formData.data" layout="vertical">
<j-form-item
:name="item.property"
v-for="item in metadata.properties"
:key="item"
:label="item.name"
:rules="[
{
required: !!item?.type?.expands?.required,
message: `${
item.type.type === 'enum'
? '请选择'
: '请输入'
}${item.name}`,
},
]"
>
<j-input
placeholder="请输入"
v-if="item.type.type === 'string'"
v-model:value="formData.data[item.property]"
></j-input>
<j-input-password
placeholder="请输入"
v-if="item.type.type === 'password'"
v-model:value="formData.data[item.property]"
></j-input-password>
<j-select
placeholder="请选择"
v-if="item.type.type === 'enum'"
v-model:value="formData.data[item.name]"
>
<j-select-option
v-for="el in item?.type?.type === 'enum' &&
item?.type?.elements
? item?.type?.elements
: []"
:key="el"
:value="el.value"
>
{{ el.text }}
</j-select-option>
</j-select>
</j-form-item>
</j-form>
<Title data="存储策略">
<template #extra>
<j-tooltip
title="若修改存储策略,需要手动做数据迁移,平台只能搜索最新存储策略中的数据"
>
<AIcon
type="QuestionCircleOutlined"
style="margin-left: 2px"
/>
</j-tooltip>
</template>
</Title>
<j-form layout="vertical">
<j-form-item>
<j-select ref="select" v-model:value="form.storePolicy">
<j-select-option
v-for="(item, index) in storageList"
:key="index"
:value="item.id"
>{{ item.name }}</j-select-option
>
</j-select>
</j-form-item>
</j-form>
<PermissionButton
type="primary"
@click="submitDevice"
hasPermission="device/Instance:update"
>保存</PermissionButton
>
</j-col>
<j-col
:span="12"
v-if="config?.routes && config?.routes?.length > 0"
>
<div class="info">
<div>
<div style="font-weight: 600; margin: 0 0 10 px 0">
{{
access?.description ||
dataSource.find(
(item) => item?.id === access?.provider,
)?.description
access?.provider === 'mqtt-server-gateway' ||
access?.provider === 'mqtt-client-gateway'
? 'topic'
: 'URL信息'
}}
</div>
</div>
<div class="item-style">
<Title data="消息协议"></Title>
<div>
{{ access?.protocolDetail?.name }}
</div>
<!-- 显示md文件内容 -->
<div
v-if="config?.document"
v-html="markdownToHtml"
></div>
</div>
<div class="item-style">
<Title data="连接信息"></Title>
<div v-if="access?.channelInfo?.addresses.length > 0">
<div
v-for="item in access?.channelInfo?.addresses"
:key="item.address"
>
<j-badge
:color="
item.health === -1 ? 'red' : 'green'
"
:text="item.address"
>
</j-badge>
</div>
</div>
<div v-else>{{ '暂无连接信息' }}</div>
</div>
<Title
v-if="metadata?.name"
:data="metadata?.name"
class="config"
>
<template #extra>
<j-tooltip
title="此配置来自于产品接入方式所选择的协议"
>
<AIcon
type="QuestionCircleOutlined"
style="margin-left: 2px"
/>
</j-tooltip>
</template>
</Title>
<j-form
ref="formRef"
:model="formData.data"
layout="vertical"
>
<j-form-item
:name="item.property"
v-for="item in metadata.properties"
:key="item"
:label="item.name"
:rules="[
{
required: !!item?.type?.expands?.required,
message: `${
item.type.type === 'enum'
? '请选择'
: '请输入'
}${item.name}`,
},
]"
<j-table
:columns="
config.id === 'MQTT' ? columnsMQTT : columnsHTTP
"
:data-source="config?.routes"
:pagination="false"
:scroll="{ y: 500 }"
>
<j-input
placeholder="请输入"
v-if="item.type.type === 'string'"
v-model:value="formData.data[item.property]"
></j-input>
<j-input-password
placeholder="请输入"
v-if="item.type.type === 'password'"
v-model:value="formData.data[item.property]"
></j-input-password>
<j-select
placeholder="请选择"
v-if="item.type.type === 'enum'"
v-model:value="formData.data[item.name]"
>
<j-select-option
v-for="el in item?.type?.type === 'enum' &&
item?.type?.elements
? item?.type?.elements
: []"
:key="el"
:value="el.value"
>
{{ el.text }}
</j-select-option>
</j-select>
</j-form-item>
</j-form>
<Title data="存储策略">
<template #extra>
<j-tooltip
title="若修改存储策略,需要手动做数据迁移,平台只能搜索最新存储策略中的数据"
>
<AIcon
type="QuestionCircleOutlined"
style="margin-left: 2px"
/>
</j-tooltip>
</template>
</Title>
<j-form layout="vertical">
<j-form-item>
<j-select
ref="select"
v-model:value="form.storePolicy"
>
<j-select-option
v-for="(item, index) in storageList"
:key="index"
:value="item.id"
>{{ item.name }}</j-select-option
>
</j-select>
</j-form-item>
</j-form>
<PermissionButton
type="primary"
@click="submitDevice"
hasPermission="device/Instance:update"
>保存</PermissionButton
>
</j-col>
<j-col
:span="12"
v-if="config?.routes && config?.routes?.length > 0"
>
<div class="info">
<div>
<div style="font-weight: 600; margin: 0 0 10 px 0">
{{
access?.provider ===
'mqtt-server-gateway' ||
access?.provider === 'mqtt-client-gateway'
? 'topic'
: 'URL信息'
}}
</div>
<j-table
:columns="
config.id === 'MQTT'
? columnsMQTT
: columnsHTTP
"
:data-source="config?.routes"
:pagination="false"
:scroll="{ y: 500 }"
>
<template #bodyCell="{ text, column, record }">
<template v-if="column.key === 'topic'">
<j-tooltip
placement="topLeft"
:title="text"
>
<div class="ellipsis-style">
{{ text }}
</div>
</j-tooltip>
</template>
<template v-if="column.key === 'stream'">
<div>{{ getStream(record) }}</div>
</template>
<template
v-if="column.key === 'description'"
<template #bodyCell="{ text, column, record }">
<template v-if="column.key === 'topic'">
<j-tooltip
placement="topLeft"
:title="text"
>
<j-tooltip
placement="topLeft"
:title="text"
>
<div class="ellipsis-style">
{{ text }}
</div>
</j-tooltip>
</template>
<template v-if="column.key === 'address'">
<j-tooltip
placement="topLeft"
:title="text"
>
<div class="ellipsis-style">
{{ text }}
</div>
</j-tooltip>
</template>
<template v-if="column.key === 'example'">
<j-tooltip
placement="topLeft"
:title="text"
>
<div class="ellipsis-style">
{{ text }}
</div>
</j-tooltip>
</template>
<div class="ellipsis-style">
{{ text }}
</div>
</j-tooltip>
</template>
</j-table>
</div>
<template v-if="column.key === 'stream'">
<div>{{ getStream(record) }}</div>
</template>
<template v-if="column.key === 'description'">
<j-tooltip
placement="topLeft"
:title="text"
>
<div class="ellipsis-style">
{{ text }}
</div>
</j-tooltip>
</template>
<template v-if="column.key === 'address'">
<j-tooltip
placement="topLeft"
:title="text"
>
<div class="ellipsis-style">
{{ text }}
</div>
</j-tooltip>
</template>
<template v-if="column.key === 'example'">
<j-tooltip
placement="topLeft"
:title="text"
>
<div class="ellipsis-style">
{{ text }}
</div>
</j-tooltip>
</template>
</template>
</j-table>
</div>
</j-col>
</j-row>
</div>
</j-card>
</div>
</j-col>
</j-row>
</div>
<!-- 选择设备 -->
<j-modal
title="设备接入配置"

View File

@ -90,11 +90,19 @@
>应用配置</PermissionButton
>
</template>
<component
:is="tabs[productStore.tabActiveKey]"
:class="productStore.tabActiveKey === 'Metadata' ? 'metedata' : ''"
v-bind="{ type: 'product' }"
/>
<FullPage>
<j-card :bordered="false">
<component
:is="tabs[productStore.tabActiveKey]"
:class="
productStore.tabActiveKey === 'Metadata'
? 'metedata'
: ''
"
v-bind="{ type: 'product' }"
/>
</j-card>
</FullPage>
</page-container>
</template>

View File

@ -5,152 +5,167 @@
target="product-manage"
@search="handleSearch"
/>
<JProTable
:columns="columns"
:request="queryProductList"
ref="tableRef"
:defaultParams="{
sorts: [{ name: 'createTime', order: 'desc' }],
}"
:params="params"
>
<template #headerTitle>
<j-space>
<PermissionButton
type="primary"
@click="add"
hasPermission="device/Product:add"
>
<template #icon><AIcon type="PlusOutlined" /></template>
新增
</PermissionButton>
<j-upload
name="file"
accept=".json"
:showUploadList="false"
:before-upload="beforeUpload"
>
<PermissionButton hasPermission="device/Product:import"
>导入</PermissionButton
<FullPage>
<JProTable
:columns="columns"
:request="queryProductList"
ref="tableRef"
:defaultParams="{
sorts: [{ name: 'createTime', order: 'desc' }],
}"
:params="params"
>
<template #headerTitle>
<j-space>
<PermissionButton
type="primary"
@click="add"
hasPermission="device/Product:add"
>
</j-upload>
</j-space>
</template>
<template #deviceType="slotProps">
<div>{{ slotProps.deviceType.text }}</div>
</template>
<template #card="slotProps">
<CardBox
:value="slotProps"
:actions="getActions(slotProps, 'card')"
v-bind="slotProps"
:active="_selectedRowKeys.includes(slotProps.id)"
:status="slotProps.state"
@click="handleView(slotProps.id)"
:statusText="slotProps.state === 1 ? '正常' : '禁用'"
:statusNames="{
1: 'processing',
0: 'error',
}"
>
<template #img>
<slot name="img">
<img
:src="
slotProps.photoUrl ||
getImage('/device-product.png')
"
class="productImg"
/>
</slot>
</template>
<template #content>
<Ellipsis style="width: calc(100% - 100px)"
><span
style="font-weight: 600; font-size: 16px"
<template #icon
><AIcon type="PlusOutlined"
/></template>
新增
</PermissionButton>
<j-upload
name="file"
accept=".json"
:showUploadList="false"
:before-upload="beforeUpload"
>
<PermissionButton
hasPermission="device/Product:import"
>导入</PermissionButton
>
{{ slotProps.name }}
</span></Ellipsis
>
<j-row>
<j-col :span="12">
<div class="card-item-content-text">
设备类型
</div>
<div>{{ slotProps?.deviceType?.text }}</div>
</j-col>
<j-col :span="12">
<div class="card-item-content-text">
接入方式
</div>
<Ellipsis
><div>
{{
slotProps?.accessName
? slotProps?.accessName
: '未接入'
}}
</div></Ellipsis
>
</j-col>
</j-row>
</template>
<template #actions="item">
<PermissionButton
:disabled="item.disabled"
:popConfirm="item.popConfirm"
:tooltip="{
...item.tooltip,
}"
@click="item.onClick"
:hasPermission="item.key ==='view' ? true : 'device/Product:' + 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
:text="slotProps.state === 1 ? '正常' : '禁用'"
:status="slotProps.state"
:statusNames="{
1: 'processing',
0: 'error',
}"
/>
</template>
<template #action="slotProps">
<j-space :size="16">
<template
v-for="i in getActions(slotProps, 'table')"
:key="i.key"
</j-upload>
</j-space>
</template>
<template #deviceType="slotProps">
<div>{{ slotProps.deviceType.text }}</div>
</template>
<template #card="slotProps">
<CardBox
:value="slotProps"
:actions="getActions(slotProps, 'card')"
v-bind="slotProps"
:active="_selectedRowKeys.includes(slotProps.id)"
:status="slotProps.state"
@click="handleView(slotProps.id)"
:statusText="slotProps.state === 1 ? '正常' : '禁用'"
:statusNames="{
1: 'processing',
0: 'error',
}"
>
<PermissionButton
:disabled="i.disabled"
:popConfirm="i.popConfirm"
:hasPermission="i.key === 'view' ? true : 'device/Product:' + i.key"
:tooltip="{
...i.tooltip,
}"
@click="i.onClick"
type="link"
style="padding: 0px"
:danger="i.key === 'delete'"
<template #img>
<slot name="img">
<img
:src="
slotProps.photoUrl ||
getImage('/device-product.png')
"
class="productImg"
/>
</slot>
</template>
<template #content>
<Ellipsis style="width: calc(100% - 100px)"
><span
style="font-weight: 600; font-size: 16px"
>
{{ slotProps.name }}
</span></Ellipsis
>
<j-row>
<j-col :span="12">
<div class="card-item-content-text">
设备类型
</div>
<div>{{ slotProps?.deviceType?.text }}</div>
</j-col>
<j-col :span="12">
<div class="card-item-content-text">
接入方式
</div>
<Ellipsis
><div>
{{
slotProps?.accessName
? slotProps?.accessName
: '未接入'
}}
</div></Ellipsis
>
</j-col>
</j-row>
</template>
<template #actions="item">
<PermissionButton
:disabled="item.disabled"
:popConfirm="item.popConfirm"
:tooltip="{
...item.tooltip,
}"
@click="item.onClick"
:hasPermission="
item.key === 'view'
? true
: 'device/Product:' + 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
:text="slotProps.state === 1 ? '正常' : '禁用'"
:status="slotProps.state"
:statusNames="{
1: 'processing',
0: 'error',
}"
/>
</template>
<template #action="slotProps">
<j-space :size="16">
<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"
:hasPermission="
i.key === 'view'
? true
: 'device/Product:' + i.key
"
:tooltip="{
...i.tooltip,
}"
@click="i.onClick"
type="link"
style="padding: 0px"
:danger="i.key === 'delete'"
>
<template #icon
><AIcon :type="i.icon"
/></template>
</PermissionButton>
</template>
</j-space>
</template>
</JProTable>
</FullPage>
<!-- 新增编辑 -->
<Save ref="saveRef" :isAdd="isAdd" :title="title" @success="refresh" />
</page-container>
@ -181,8 +196,8 @@ import { typeOptions } from '@/components/Search/util';
import Save from './Save/index.vue';
import { useMenuStore } from 'store/menu';
import { useRoute } from 'vue-router';
import {useRouterParams} from "@/utils/hooks/useParams";
import { accessConfigTypeFilter } from '@/utils/setting'
import { useRouterParams } from '@/utils/hooks/useParams';
import { accessConfigTypeFilter } from '@/utils/setting';
/**
* 表格数据
*/
@ -196,21 +211,21 @@ const columns = [
dataIndex: 'id',
key: 'id',
scopedSlots: true,
width:200,
width: 200,
ellipsis: true,
},
{
title: '产品名称',
dataIndex: 'name',
key: 'name',
width:220,
width: 220,
ellipsis: true,
},
{
title: '接入方式',
dataIndex: 'accessName',
key: 'accessName',
width:220,
width: 220,
ellipsis: true,
},
{
@ -219,7 +234,7 @@ const columns = [
key: 'deviceType',
scopedSlots: true,
ellipsis: true,
width:120,
width: 120,
},
{
title: '状态',
@ -227,7 +242,7 @@ const columns = [
key: 'state',
scopedSlots: true,
ellipsis: true,
width:90,
width: 90,
},
{
title: '说明',
@ -434,7 +449,7 @@ const query = reactive({
key: 'id',
search: {
type: 'string',
defaultTermType: 'eq'
defaultTermType: 'eq',
},
},
{
@ -446,8 +461,8 @@ const query = reactive({
options: () => {
return new Promise((resolve) => {
getProviders().then((resp: any) => {
const data = resp.result || []
resolve(accessConfigTypeFilter(data))
const data = resp.result || [];
resolve(accessConfigTypeFilter(data));
});
});
},
@ -592,9 +607,9 @@ const saveRef = ref();
const handleSearch = (e: any) => {
params.value = e;
};
const routerParams = useRouterParams()
const routerParams = useRouterParams();
onMounted(() => {
if(routerParams.params?.value.save){
if (routerParams.params?.value.save) {
add();
}
});

View File

@ -1,5 +1,4 @@
<template>
<j-card>
<div class='device-detail-metadata' style="position: relative;">
<div class="tips">
<j-tooltip :title="instanceStore.detail?.independentMetadata && type === 'device'
@ -44,7 +43,6 @@
<Import v-if="visible" v-model:visible="visible" :type="type" @close="visible = false" />
<Cat v-model:visible="cat" @close="cat = false" :type="type" />
</div>
</j-card>
</template>
<script setup lang="ts" name="Metadata">
import PermissionButton from '@/components/PermissionButton/index.vue'

View File

@ -1,58 +1,79 @@
<template>
<page-container :tabList="list" @tabChange="onTabChange" :tabActiveKey="tab">
<div v-if="tab=='config'">
<page-container
:tabList="list"
@tabChange="onTabChange"
:tabActiveKey="tab"
>
<div v-if="tab == 'config'">
<j-row :gutter="24">
<j-col :span="14">
<div class="alarm-level">
<j-card
:headStyle="{ borderBottom: 'none', padding: 0 }"
:bodyStyle="{ padding: 0 }"
:bordered="false"
>
<template #title>
<div class="alarmLevelTitle">告警级别配置</div>
</template>
<div
v-for="(item, i) in levels"
:key="i"
class="alarmInputItem"
<FullPage>
<div class="alarm-level">
<j-card
:headStyle="{
borderBottom: 'none',
padding: 0,
}"
:bodyStyle="{ padding: 0 }"
:bordered="false"
>
<div>
<img
:src="
getImage(`/alarm/alarm${i + 1}.png`)
"
alt=""
/>
<span>{{ `级别${i + 1}` }}</span>
<template #title>
<div class="alarmLevelTitle">
告警级别配置
</div>
</template>
<div
v-for="(item, i) in levels"
:key="i"
class="alarmInputItem"
>
<div>
<img
:src="
getImage(
`/alarm/alarm${i + 1}.png`,
)
"
alt=""
/>
<span>{{ `级别${i + 1}` }}</span>
</div>
<div>
<j-input
type="text"
v-model:value="item.title"
:maxlength="64"
></j-input>
</div>
</div>
<div>
<j-input
type="text"
v-model:value="item.title"
:maxlength="64"
></j-input>
</div>
</div>
</j-card>
<!-- <j-button
</j-card>
<!-- <j-button
type="primary"
size="middle"
@click="handleSaveLevel"
>保存</j-button
> -->
<PermissionButton type="primary" size="middle" @click="handleSaveLevel" hasPermission="rule-engine/Alarm/Config:update">保存</PermissionButton>
</div>
<PermissionButton
type="primary"
size="middle"
@click="handleSaveLevel"
hasPermission="rule-engine/Alarm/Config:update"
>保存</PermissionButton
>
</div>
</FullPage>
</j-col>
<j-col :span="10">
<div class="description">
<h1>功能说明</h1>
<div>
1告警级别用于描述告警的严重程度请根据业务管理方式进行自定义
<FullPage>
<div class="description">
<h1>功能说明</h1>
<div>
1告警级别用于描述告警的严重程度请根据业务管理方式进行自定义
</div>
<div>2告警级别将会在告警配置中被引用</div>
<div>3最多可配置5个级别</div>
</div>
<div>2告警级别将会在告警配置中被引用</div>
<div>3最多可配置5个级别</div>
</div>
</FullPage>
</j-col>
</j-row>
</div>
@ -65,7 +86,7 @@ import { getImage } from '@/utils/comm';
import { queryLevel, saveLevel } from '@/api/rule-engine/config';
import { LevelItem } from './typing';
import { message } from 'jetlinks-ui-components';
import Io from './Io/index.vue'
import Io from './Io/index.vue';
const list = ref([
{
key: 'config',
@ -77,7 +98,7 @@ const list = ref([
},
]);
let levels = ref<LevelItem[]>([]);
let tab = ref<'io'|'config'|string>('config');
let tab = ref<'io' | 'config' | string>('config');
const getAlarmLevel = () => {
queryLevel().then((res: any) => {
if (res.status == 200) {
@ -133,9 +154,10 @@ const onTabChange = (e: string) => {
font-size: 14px;
background-color: #fff;
h1 {
margin: 16px 0;
color: rgba(#000, 0.85);
font-weight: bold;
font-size: 14px;}
margin: 16px 0;
color: rgba(#000, 0.85);
font-weight: bold;
font-size: 14px;
}
}
</style>

View File

@ -1,67 +1,74 @@
<template>
<div>
<j-form layout="vertical" :rules="rule" :model="form" ref="formRef">
<j-row :gutter="24">
<j-col :span="12">
<j-form-item label="名称" name="name">
<j-input
placeholder="请输入名称"
v-model:value="form.name"
></j-input> </j-form-item
></j-col>
<j-col :span="12">
<j-form-item label="类型" name="targetType">
<j-select
:options="options"
v-model:value="form.targetType"
:disabled="selectDisable"
></j-select>
</j-form-item>
</j-col>
</j-row>
<j-form-item label="级别" name="level">
<j-radio-group v-model:value="form.level" class="levelSelect">
<j-radio-button
v-for="(item, index) in levelOption"
:key="index"
:value="item.value"
<FullPage>
<div>
<j-form layout="vertical" :rules="rule" :model="form" ref="formRef">
<j-row :gutter="24">
<j-col :span="12">
<j-form-item label="名称" name="name">
<j-input
placeholder="请输入名称"
v-model:value="form.name"
></j-input> </j-form-item
></j-col>
<j-col :span="12">
<j-form-item label="类型" name="targetType">
<j-select
:options="options"
v-model:value="form.targetType"
:disabled="selectDisable"
></j-select>
</j-form-item>
</j-col>
</j-row>
<j-form-item label="级别" name="level">
<j-radio-group
v-model:value="form.level"
class="levelSelect"
>
<div
style="
text-align: center;
margin-top: 10px;
font-size: 15px;
width: 90%;
"
<j-radio-button
v-for="(item, index) in levelOption"
:key="index"
:value="item.value"
>
<img
:src="getImage(`/alarm/alarm${index + 1}.png`)"
style="height: 40px"
alt=""
/>{{ item.label }}
</div>
</j-radio-button>
</j-radio-group>
</j-form-item>
<j-form-item label="说明" name="description">
<j-textarea
v-model:value="form.description"
showCount
:maxlength="200"
></j-textarea>
</j-form-item>
<PermissionButton
type="primary"
:loading="loading"
@click="handleSave"
:hasPermission="[
'rule-engine/Alarm/Configuration:add',
'rule-engine/Alarm/Configuration:update',
]"
>保存</PermissionButton
>
</j-form>
</div>
<div
style="
text-align: center;
margin-top: 10px;
font-size: 15px;
width: 90%;
"
>
<img
:src="
getImage(`/alarm/alarm${index + 1}.png`)
"
style="height: 40px"
alt=""
/>{{ item.label }}
</div>
</j-radio-button>
</j-radio-group>
</j-form-item>
<j-form-item label="说明" name="description">
<j-textarea
v-model:value="form.description"
showCount
:maxlength="200"
></j-textarea>
</j-form-item>
<PermissionButton
type="primary"
:loading="loading"
@click="handleSave"
:hasPermission="[
'rule-engine/Alarm/Configuration:add',
'rule-engine/Alarm/Configuration:update',
]"
>保存</PermissionButton
>
</j-form>
</div>
</FullPage>
</template>
<script lang="ts" setup>

View File

@ -1,86 +1,90 @@
<template>
<JProTable
model="CARD"
:request="query"
:defaultParams="{
sorts: [{ name: 'createTime', order: 'desc' }],
terms,
}"
ref="actionRef"
>
<template #headerTitle>
<j-space>
<PermissionButton
type="primary"
@click="showModal"
hasPermission="rule-engine/Alarm/Configuration:add"
>
<template #icon><AIcon type="PlusOutlined" /></template>
新增
</PermissionButton>
</j-space>
</template>
<template #card="slotProps">
<CardBox
:value="slotProps"
:actions="getActions(slotProps, 'card')"
:status="slotProps.state?.value"
:statusText="slotProps.state?.text"
:statusNames="{
started: 'processing',
disable: 'error',
}"
>
<template #type>
<span
><img
:height="16"
:src="typeMap.get(slotProps.triggerType)?.icon"
style="margin-right: 5px"
/>{{ typeMap.get(slotProps.triggerType)?.text }}</span
>
</template>
<template #img>
<img :src="typeMap.get(slotProps.triggerType)?.img" />
</template>
<template #content>
<Ellipsis style="width: calc(100% - 100px)">
<span style="font-size: 16px; font-weight: 600">
{{ slotProps.name }}
</span>
</Ellipsis>
<Ellipsis :lineClamp="2">
<div class="subTitle">
说明{{
slotProps?.description ||
typeMap.get(slotProps.triggerType)?.tip
}}
</div>
</Ellipsis>
</template>
<template #actions="item">
<FullPage>
<JProTable
model="CARD"
:request="query"
:defaultParams="{
sorts: [{ name: 'createTime', order: 'desc' }],
terms,
}"
ref="actionRef"
>
<template #headerTitle>
<j-space>
<PermissionButton
:disabled="item.disabled"
:popConfirm="item.popConfirm"
:tooltip="{
...item.tooltip,
}"
@click="item.onClick"
:hasPermission="'rule-engine/Scene:' + item.key"
type="primary"
@click="showModal"
hasPermission="rule-engine/Alarm/Configuration: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>
</JProTable>
</j-space>
</template>
<template #card="slotProps">
<CardBox
:value="slotProps"
:actions="getActions(slotProps, 'card')"
:status="slotProps.state?.value"
:statusText="slotProps.state?.text"
:statusNames="{
started: 'processing',
disable: 'error',
}"
>
<template #type>
<span
><img
:height="16"
:src="typeMap.get(slotProps.triggerType)?.icon"
style="margin-right: 5px"
/>{{
typeMap.get(slotProps.triggerType)?.text
}}</span
>
</template>
<template #img>
<img :src="typeMap.get(slotProps.triggerType)?.img" />
</template>
<template #content>
<Ellipsis style="width: calc(100% - 100px)">
<span style="font-size: 16px; font-weight: 600">
{{ slotProps.name }}
</span>
</Ellipsis>
<Ellipsis :lineClamp="2">
<div class="subTitle">
说明{{
slotProps?.description ||
typeMap.get(slotProps.triggerType)?.tip
}}
</div>
</Ellipsis>
</template>
<template #actions="item">
<PermissionButton
:disabled="item.disabled"
:popConfirm="item.popConfirm"
:tooltip="{
...item.tooltip,
}"
@click="item.onClick"
:hasPermission="'rule-engine/Scene:' + 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>
</JProTable>
</FullPage>
<Save
:id="id"
:type="configurationData.current?.targetType"

View File

@ -6,172 +6,182 @@
target="device-instance"
@search="handleSearch"
/>
<JProTable
:columns="columns"
:request="queryList"
:gridColumn="3"
:gridColumns="[1, 2, 3]"
ref="tableRef"
:defaultParams="{
sorts: [{ name: 'createTime', order: 'desc' }],
}"
:params="params"
>
<template #headerTitle>
<j-space>
<PermissionButton
type="primary"
@click="add"
hasPermission="rule-engine/Alarm/Configuration:add"
>
<template #icon
><AIcon type="PlusOutlined"
/></template>
新增
</PermissionButton>
</j-space>
</template>
<template #card="slotProps">
<CardBox
:value="slotProps"
:actions="getActions(slotProps, 'card')"
v-bind="slotProps"
:status="slotProps.state?.value"
:statusText="slotProps.state?.text"
:statusNames="{
enabled: 'processing',
disabled: 'error',
}"
@click="
() => {
menuStory.jumpPage(
'rule-engine/Alarm/Configuration/Save',
{},
{ id: slotProps.id },
);
}
"
>
<template #img>
<slot name="img">
<img
:src="getImage('/alarm/alarm-config.png')"
/>
</slot>
</template>
<template #content>
<Ellipsis style="width: calc(100% - 100px)">
<span style="font-weight: 600; font-size: 16px">
{{ slotProps.name }}
</span>
</Ellipsis>
<j-row>
<j-col :span="12">
<div class="content-des-title">
关联场景联动
</div>
<Ellipsis
><div>
{{ (slotProps?.scene || []).map((item: any) => item?.name).join(',') || '' }}
</div></Ellipsis
>
</j-col>
<j-col :span="12">
<div class="content-des-title">
告警级别
</div>
<div>
{{ (Store.get('default-level') || []).find((item: any) => item?.level === slotProps.level)?.title ||
slotProps.level }}
</div>
</j-col>
</j-row>
</template>
<template #actions="item">
<FullPage>
<JProTable
:columns="columns"
:request="queryList"
:gridColumn="3"
:gridColumns="[1, 2, 3]"
ref="tableRef"
: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="
'rule-engine/Alarm/Configuration:' +
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 #targetType="slotProps">
<span>{{ map[slotProps.targetType] }}</span>
</template>
<template #level="slotProps">
<j-tooltip
placement="topLeft"
:title="(Store.get('default-level') || []).find((item: any) => item?.level === slotProps.level)?.title ||
slotProps.level"
>
<div class="ellipsis">
{{ (Store.get('default-level') || []).find((item: any) => item?.level === slotProps.level)?.title ||
slotProps.level }}
</div>
</j-tooltip>
</template>
<template #sceneId="slotProps">
<span
>{{(slotProps?.scene || []).map((item: any) => item?.name).join(',') || ''}}</span
>
</template>
<template #state="slotProps">
<BadgeStatus
:text="
slotProps.state?.value === 'enabled'
? '正常'
: '禁用'
"
:status="slotProps.state?.value"
:statusNames="{
enabled: 'processing',
disabled: 'error',
}"
/>
</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="
'rule-engine/Alarm/Configuration:' + i.key
"
:danger="i.key === 'delete'"
type="primary"
@click="add"
hasPermission="rule-engine/Alarm/Configuration:add"
>
<template #icon
><AIcon :type="i.icon"
><AIcon type="PlusOutlined"
/></template>
新增
</PermissionButton>
</template>
</j-space>
</template>
</JProTable>
</j-space>
</template>
<template #card="slotProps">
<CardBox
:value="slotProps"
:actions="getActions(slotProps, 'card')"
v-bind="slotProps"
:status="slotProps.state?.value"
:statusText="slotProps.state?.text"
:statusNames="{
enabled: 'processing',
disabled: 'error',
}"
@click="
() => {
menuStory.jumpPage(
'rule-engine/Alarm/Configuration/Save',
{},
{ id: slotProps.id },
);
}
"
>
<template #img>
<slot name="img">
<img
:src="
getImage('/alarm/alarm-config.png')
"
/>
</slot>
</template>
<template #content>
<Ellipsis style="width: calc(100% - 100px)">
<span
style="
font-weight: 600;
font-size: 16px;
"
>
{{ slotProps.name }}
</span>
</Ellipsis>
<j-row>
<j-col :span="12">
<div class="content-des-title">
关联场景联动
</div>
<Ellipsis
><div>
{{ (slotProps?.scene || []).map((item: any) => item?.name).join(',') || '' }}
</div></Ellipsis
>
</j-col>
<j-col :span="12">
<div class="content-des-title">
告警级别
</div>
<div>
{{ (Store.get('default-level') || []).find((item: any) => item?.level === slotProps.level)?.title ||
slotProps.level }}
</div>
</j-col>
</j-row>
</template>
<template #actions="item">
<PermissionButton
:disabled="item.disabled"
:popConfirm="item.popConfirm"
:tooltip="{ ...item.tooltip }"
@click="item.onClick"
:hasPermission="
'rule-engine/Alarm/Configuration:' +
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 #targetType="slotProps">
<span>{{ map[slotProps.targetType] }}</span>
</template>
<template #level="slotProps">
<j-tooltip
placement="topLeft"
:title="(Store.get('default-level') || []).find((item: any) => item?.level === slotProps.level)?.title ||
slotProps.level"
>
<div class="ellipsis">
{{ (Store.get('default-level') || []).find((item: any) => item?.level === slotProps.level)?.title ||
slotProps.level }}
</div>
</j-tooltip>
</template>
<template #sceneId="slotProps">
<span
>{{(slotProps?.scene || []).map((item: any) => item?.name).join(',') || ''}}</span
>
</template>
<template #state="slotProps">
<BadgeStatus
:text="
slotProps.state?.value === 'enabled'
? '正常'
: '禁用'
"
:status="slotProps.state?.value"
:statusNames="{
enabled: 'processing',
disabled: 'error',
}"
/>
</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="
'rule-engine/Alarm/Configuration:' +
i.key
"
:danger="i.key === 'delete'"
>
<template #icon
><AIcon :type="i.icon"
/></template>
</PermissionButton>
</template>
</j-space>
</template>
</JProTable>
</FullPage>
</div>
</page-container>
</template>

View File

@ -5,48 +5,57 @@
target="alarm-log-detail"
@search="handleSearch"
/>
<JProTable
:columns="columns"
model="TABLE"
:request="queryList"
:params="params"
:defaultParams="{
terms,
sorts: [{ name: 'alarmTime', order: 'desc' }],
}"
>
<template #alarmTime="slotProps">{{
dayjs(slotProps.alarmTime).format('YYYY-MM-DD HH:mm:ss')
}}</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: 0px"
<FullPage>
<JProTable
:columns="columns"
model="TABLE"
:request="queryList"
:params="params"
:defaultParams="{
terms,
sorts: [{ name: 'alarmTime', order: 'desc' }],
}"
>
<template #alarmTime="slotProps">{{
dayjs(slotProps.alarmTime).format('YYYY-MM-DD HH:mm:ss')
}}</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>
<Info v-if="visiable" :data="current" @close="close" :description="description"/>
<PermissionButton
:disabled="i.disabled"
:popConfirm="i.popConfirm"
:tooltip="{
...i.tooltip,
}"
@click="i.onClick"
type="link"
style="padding: 0px"
>
<template #icon
><AIcon :type="i.icon"
/></template>
</PermissionButton>
</template>
</j-space>
</template>
</JProTable>
</FullPage>
<Info
v-if="visiable"
:data="current"
@close="close"
:description="description"
/>
</page-container>
</template>
<script lang="ts" setup>
import { detail, queryHistoryList } from '@/api/rule-engine/log';
import { detail as configurationDetail} from '@/api/rule-engine/configuration'
import { detail as configurationDetail } from '@/api/rule-engine/configuration';
import { useRoute } from 'vue-router';
import dayjs from 'dayjs';
import type { ActionsType } from '@/components/Table/index.vue';
@ -54,10 +63,10 @@ import { message } from 'jetlinks-ui-components';
import { useAlarmStore } from '@/store/alarm';
import Info from './info.vue';
import { storeToRefs } from 'pinia';
import {useRouterParams} from "@/utils/hooks/useParams";
import { useRouterParams } from '@/utils/hooks/useParams';
const route = useRoute();
const id = route.params?.id;
const { params: routerParams } = useRouterParams()
const { params: routerParams } = useRouterParams();
let visiable = ref(false);
let description = ref<string>();
const columns = [
@ -170,11 +179,11 @@ watchEffect(async () => {
key: 'targetName',
});
}
configurationDetail(res.result?.alarmConfigId).then((res:any)=>{
if(res.status === 200){
configurationDetail(res.result?.alarmConfigId).then((res: any) => {
if (res.status === 200) {
description.value = res.result?.description;
}
})
});
}
});
const handleSearch = (_params: any) => {
@ -185,15 +194,15 @@ const handleSearch = (_params: any) => {
* 关闭模态弹窗
*/
const close = () => {
visiable.value = false
}
visiable.value = false;
};
watchEffect(()=>{
watchEffect(() => {
current.value = details.value;
if(routerParams.value.detail && details.value){
if (routerParams.value.detail && details.value) {
visiable.value = true;
}
})
});
</script>
<style lang="less" scoped>
</style>

View File

@ -5,39 +5,43 @@
target="bind-channel"
@search="handleSearch"
/>
<JProTable
model="TABLE"
:columns="columns"
:defaultParams="{
sorts: [{ name: 'createTime', order: 'desc' }],
terms,
}"
:request="queryHandleHistory"
:params="params"
>
<template #headerTitle>
<h3>记录列表</h3>
</template>
<template #handleTime="slotsProps">
<span>
{{
dayjs(slotsProps.handleTime).format(
'YYYY-MM-DD HH:mm:ss',
)
}}
</span>
</template>
<template #handleType="slotProps">
<span>{{ slotProps.handleType.text }}</span>
</template>
<template #alarmTime="slotProps">
<span>
{{
dayjs(slotProps.alarmTime).format('YYYY-MM-DD HH:mm:ss')
}}
</span>
</template>
</JProTable>
<FullPage>
<JProTable
model="TABLE"
:columns="columns"
:defaultParams="{
sorts: [{ name: 'createTime', order: 'desc' }],
terms,
}"
:request="queryHandleHistory"
:params="params"
>
<template #headerTitle>
<h3>记录列表</h3>
</template>
<template #handleTime="slotsProps">
<span>
{{
dayjs(slotsProps.handleTime).format(
'YYYY-MM-DD HH:mm:ss',
)
}}
</span>
</template>
<template #handleType="slotProps">
<span>{{ slotProps.handleType.text }}</span>
</template>
<template #alarmTime="slotProps">
<span>
{{
dayjs(slotProps.alarmTime).format(
'YYYY-MM-DD HH:mm:ss',
)
}}
</span>
</template>
</JProTable>
</FullPage>
</page-container>
</template>

View File

@ -24,113 +24,118 @@
v-if="props.type === 'org'"
@search="search"
/>
<JProTable
:columns="columns"
:request="handleSearch"
:params="params"
:gridColumns="[1, 1, 2]"
:gridColumn="2"
model="CARD"
ref="tableRef"
>
<template #card="slotProps">
<CardBox
:value="slotProps"
v-bind="slotProps"
:actions="getActions(slotProps, 'card')"
:statusText="
data.defaultLevel.find(
(i) => i.level === slotProps.level,
)?.title || slotProps.level
"
:status="slotProps.level"
:statusNames="{
1: 'level1',
2: 'level2',
3: 'level3',
4: 'level4',
5: 'level5',
}"
>
<template #img>
<img :src="imgMap.get(slotProps.targetType)" alt="" />
</template>
<template #content>
<Ellipsis style="width: calc(100% - 100px)">
<span style="font-weight: 500">
{{ slotProps.alarmName }}
</span>
</Ellipsis>
<j-row :gutter="24">
<j-col :span="8" class="content-left">
<div class="content-left-title">
{{ titleMap.get(slotProps.targetType) }}
</div>
<Ellipsis
><div>
{{ slotProps?.targetName }}
</div></Ellipsis
>
</j-col>
<j-col :span="8">
<div class="content-right-title">
最近告警时间
</div>
<Ellipsis
><div>
{{
dayjs(slotProps?.alarmTime).format(
'YYYY-MM-DD HH:mm:ss',
)
}}
</div></Ellipsis
>
</j-col>
<j-col :span="8">
<div class="content-right-title">状态</div>
<BadgeStatus
:status="slotProps.state.value"
:statusName="{
warning: 'warning',
normal: 'default',
}"
>
</BadgeStatus
><span
:style="
slotProps.state.value === 'warning'
? 'color: #E50012'
: 'color:black'
"
>
{{ slotProps.state.text }}
<FullPage>
<JProTable
:columns="columns"
:request="handleSearch"
:params="params"
:gridColumns="[1, 1, 2]"
:gridColumn="2"
model="CARD"
ref="tableRef"
>
<template #card="slotProps">
<CardBox
:value="slotProps"
v-bind="slotProps"
:actions="getActions(slotProps, 'card')"
:statusText="
data.defaultLevel.find(
(i) => i.level === slotProps.level,
)?.title || slotProps.level
"
:status="slotProps.level"
:statusNames="{
1: 'level1',
2: 'level2',
3: 'level3',
4: 'level4',
5: 'level5',
}"
>
<template #img>
<img
:src="imgMap.get(slotProps.targetType)"
alt=""
/>
</template>
<template #content>
<Ellipsis style="width: calc(100% - 100px)">
<span style="font-weight: 500">
{{ slotProps.alarmName }}
</span>
</j-col>
</j-row>
</template>
<template #actions="item">
<PermissionButton
:disabled="
item.key === 'solve' &&
slotProps.state.value === 'normal'
"
:tooltip="{
...item.tooltip,
}"
@click="item.onClick"
:hasPermission="
item.key == 'solve'
? 'rule-engine/Alarm/Log:action'
: 'rule-engine/Alarm/Log:view'
"
>
<AIcon :type="item.icon" />
<span>{{ item?.text }}</span>
</PermissionButton>
</template>
</CardBox>
</template>
</JProTable>
</Ellipsis>
<j-row :gutter="24">
<j-col :span="8" class="content-left">
<div class="content-left-title">
{{ titleMap.get(slotProps.targetType) }}
</div>
<Ellipsis
><div>
{{ slotProps?.targetName }}
</div></Ellipsis
>
</j-col>
<j-col :span="8">
<div class="content-right-title">
最近告警时间
</div>
<Ellipsis
><div>
{{
dayjs(
slotProps?.alarmTime,
).format('YYYY-MM-DD HH:mm:ss')
}}
</div></Ellipsis
>
</j-col>
<j-col :span="8">
<div class="content-right-title">状态</div>
<BadgeStatus
:status="slotProps.state.value"
:statusName="{
warning: 'warning',
normal: 'default',
}"
>
</BadgeStatus
><span
:style="
slotProps.state.value === 'warning'
? 'color: #E50012'
: 'color:black'
"
>
{{ slotProps.state.text }}
</span>
</j-col>
</j-row>
</template>
<template #actions="item">
<PermissionButton
:disabled="
item.key === 'solve' &&
slotProps.state.value === 'normal'
"
:tooltip="{
...item.tooltip,
}"
@click="item.onClick"
:hasPermission="
item.key == 'solve'
? 'rule-engine/Alarm/Log:action'
: 'rule-engine/Alarm/Log:view'
"
>
<AIcon :type="item.icon" />
<span>{{ item?.text }}</span>
</PermissionButton>
</template>
</CardBox>
</template>
</JProTable>
</FullPage>
<SolveComponent
:data="data"
v-if="data.solveVisible"

View File

@ -6,127 +6,138 @@
target="device-instance"
@search="handleSearch"
/>
<JProTable
:columns="columns"
:request="queryList"
ref="tableRef"
:defaultParams="{
sorts: [{ name: 'createTime', order: 'desc' }],
}"
:params="params"
>
<template #headerTitle>
<j-space>
<PermissionButton
type="primary"
@click="add"
hasPermission="rule-engine/Instance:add"
>
<template #icon
><AIcon type="PlusOutlined"
/></template>
新增
</PermissionButton>
</j-space>
</template>
<template #card="slotProps">
<CardBox
:value="slotProps"
:actions="getActions(slotProps, 'card')"
v-bind="slotProps"
:status="slotProps.state?.value"
:statusText="slotProps.state?.text"
@click="openRuleEditor"
:statusNames="{
started: 'processing',
disable: 'error',
}"
>
<template #img>
<slot name="img">
<img :src="getImage('/device-product.png')" />
</slot>
</template>
<template #content>
<Ellipsis style="width: calc(100% - 100px)">
<span style="font-weight: 600; font-size: 16px">
{{ slotProps.name }}
</span>
</Ellipsis>
<j-row>
<j-col :span="12">
<Ellipsis>
<div>
{{ slotProps.description }}
</div>
</Ellipsis>
</j-col>
</j-row>
</template>
<template #actions="item">
<FullPage>
<JProTable
:columns="columns"
:request="queryList"
ref="tableRef"
:defaultParams="{
sorts: [{ name: 'createTime', order: 'desc' }],
}"
:params="params"
>
<template #headerTitle>
<j-space>
<PermissionButton
:disabled="item.disabled"
:popConfirm="item.popConfirm"
:tooltip="{
...item.tooltip,
}"
:hasPermission="
'rule-engine/Instance:' + item.key
"
@click="item.onClick"
>
<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
:text="
slotProps.state?.value === 'started'
? '正常'
: '禁用'
"
:status="slotProps.state?.value"
:statusNames="{
started: 'processing',
disable: 'error',
}"
/>
</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="'rule-engine/Instance:' + i.key"
:danger="i.key === 'delete'"
type="primary"
@click="add"
hasPermission="rule-engine/Instance:add"
>
<template #icon
><AIcon :type="i.icon"
><AIcon type="PlusOutlined"
/></template>
新增
</PermissionButton>
</template>
</j-space>
</template>
</JProTable>
</j-space>
</template>
<template #card="slotProps">
<CardBox
:value="slotProps"
:actions="getActions(slotProps, 'card')"
v-bind="slotProps"
:status="slotProps.state?.value"
:statusText="slotProps.state?.text"
@click="openRuleEditor"
:statusNames="{
started: 'processing',
disable: 'error',
}"
>
<template #img>
<slot name="img">
<img
:src="getImage('/device-product.png')"
/>
</slot>
</template>
<template #content>
<Ellipsis style="width: calc(100% - 100px)">
<span
style="
font-weight: 600;
font-size: 16px;
"
>
{{ slotProps.name }}
</span>
</Ellipsis>
<j-row>
<j-col :span="12">
<Ellipsis>
<div>
{{ slotProps.description }}
</div>
</Ellipsis>
</j-col>
</j-row>
</template>
<template #actions="item">
<PermissionButton
:disabled="item.disabled"
:popConfirm="item.popConfirm"
:tooltip="{
...item.tooltip,
}"
:hasPermission="
'rule-engine/Instance:' + item.key
"
@click="item.onClick"
>
<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
:text="
slotProps.state?.value === 'started'
? '正常'
: '禁用'
"
:status="slotProps.state?.value"
:statusNames="{
started: 'processing',
disable: 'error',
}"
/>
</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="
'rule-engine/Instance:' + i.key
"
:danger="i.key === 'delete'"
>
<template #icon
><AIcon :type="i.icon"
/></template>
</PermissionButton>
</template>
</j-space>
</template>
</JProTable>
</FullPage>
<!-- 新增编辑 -->
<Save
:data="current"
@ -151,11 +162,11 @@ import { getImage } from '@/utils/comm';
import { message } from 'jetlinks-ui-components';
import Save from './Save/index.vue';
import { SystemConst } from '@/utils/consts';
import {useRouterParams} from "@/utils/hooks/useParams";
import { useRouterParams } from '@/utils/hooks/useParams';
const params = ref<Record<string, any>>({});
let visiable = ref(false);
const tableRef = ref<Record<string, any>>({});
const { params: routeParams } = useRouterParams()
const { params: routeParams } = useRouterParams();
const query = {
columns: [
{