feat: 告警配置
This commit is contained in:
parent
849bfbdaad
commit
6ba0f0cbb6
|
@ -34,4 +34,13 @@ export const save = (data:any) =>server.post('/alarm/config',data);
|
|||
/**
|
||||
* 获取基础设置数据
|
||||
*/
|
||||
export const detail = (id:string) => server.get(`/alarm/config/${id}`);
|
||||
export const detail = (id:string) => server.get(`/alarm/config/${id}`);
|
||||
/**
|
||||
* 解除场景联动绑定
|
||||
*/
|
||||
export const unbindScene = (id:string,data:any) => server.post(`/alarm/rule/bind/${id}/_delete`,data);
|
||||
|
||||
/**
|
||||
* 保存关联场景
|
||||
*/
|
||||
export const bindScene = (data:any) => server.patch("/alarm/rule/bind",data)
|
|
@ -1,37 +1,47 @@
|
|||
import { defineStore } from "pinia";
|
||||
|
||||
export const useAlarmStore = defineStore('alarm',()=>{
|
||||
const data = reactive({
|
||||
tab: 'all',
|
||||
current: {},
|
||||
solveVisible: false,
|
||||
logVisible: false,
|
||||
defaultLevel: [],
|
||||
columns: [
|
||||
{
|
||||
dataIndex: 'alarmConfigName',
|
||||
title: '告警名称',
|
||||
// hideInSearch: true,
|
||||
},
|
||||
{
|
||||
dataIndex: 'alarmTime',
|
||||
title: '告警时间',
|
||||
valueType: 'dateTime',
|
||||
},
|
||||
{
|
||||
dataIndex: 'description',
|
||||
title: '说明',
|
||||
// hideInSearch: true,
|
||||
},
|
||||
{
|
||||
dataIndex: 'action',
|
||||
title: '操作',
|
||||
hideInSearch: true,
|
||||
valueType: 'option',
|
||||
},
|
||||
],
|
||||
})
|
||||
return {
|
||||
data
|
||||
export const useAlarmStore = defineStore('alarm', () => {
|
||||
const data = reactive({
|
||||
tab: 'all',
|
||||
current: {},
|
||||
solveVisible: false,
|
||||
logVisible: false,
|
||||
defaultLevel: [],
|
||||
columns: [
|
||||
{
|
||||
dataIndex: 'alarmConfigName',
|
||||
title: '告警名称',
|
||||
// hideInSearch: true,
|
||||
},
|
||||
{
|
||||
dataIndex: 'alarmTime',
|
||||
title: '告警时间',
|
||||
valueType: 'dateTime',
|
||||
},
|
||||
{
|
||||
dataIndex: 'description',
|
||||
title: '说明',
|
||||
// hideInSearch: true,
|
||||
},
|
||||
{
|
||||
dataIndex: 'action',
|
||||
title: '操作',
|
||||
hideInSearch: true,
|
||||
valueType: 'option',
|
||||
},
|
||||
],
|
||||
})
|
||||
return {
|
||||
data
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
export const useAlarmConfigurationStore = defineStore('alarmConfigration', () => {
|
||||
const configurationData = reactive({
|
||||
current:{
|
||||
|
||||
}
|
||||
})
|
||||
return { configurationData }
|
||||
})
|
|
@ -61,10 +61,13 @@ import { getImage } from '@/utils/comm';
|
|||
import { message } from 'ant-design-vue';
|
||||
import { useMenuStore } from '@/store/menu';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { Store } from 'jetlinks-store';
|
||||
import { useAlarmConfigurationStore } from '@/store/alarm';
|
||||
import { storeToRefs } from 'pinia';
|
||||
const route = useRoute();
|
||||
const id = route.query?.id;
|
||||
let selectDisable = ref(false);
|
||||
const alarmConfigurationStore = useAlarmConfigurationStore();
|
||||
let { configurationData } = storeToRefs(alarmConfigurationStore);
|
||||
const queryData = () => {
|
||||
if (id) {
|
||||
detail(id).then((res) => {
|
||||
|
@ -73,7 +76,7 @@ const queryData = () => {
|
|||
form.name = res?.result?.name;
|
||||
form.targetType = res?.result?.targetType;
|
||||
form.description = res?.result?.description;
|
||||
Store.set('configuration-data', res.result);
|
||||
configurationData.value.current = res.result;
|
||||
query({
|
||||
terms: [
|
||||
{
|
||||
|
@ -183,7 +186,7 @@ const handleSave = async () => {
|
|||
{ id: res.result?.id },
|
||||
);
|
||||
if (!id) {
|
||||
Store.set('configuration-data', res.result);
|
||||
configurationData.value.current = res.result;
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
<template>
|
||||
<div>
|
||||
<TabComponent type="detail" :id="id"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import TabComponent from '@/views/rule-engine/Alarm/Log/TabComponent/indev.vue'
|
||||
import { useRoute } from 'vue-router';
|
||||
const route = useRoute();
|
||||
const id = route.query?.id
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
</style>
|
|
@ -0,0 +1,233 @@
|
|||
<template>
|
||||
<a-modal
|
||||
visible
|
||||
title="新增"
|
||||
okText="确定"
|
||||
cancelText="取消"
|
||||
:width="1000"
|
||||
@cancel="closeModal"
|
||||
@ok="saveCorrelation"
|
||||
>
|
||||
<Search :columns="columns" @search="handleSearch"></Search>
|
||||
<div style="height: 500px; overflow-y: auto">
|
||||
<JTable
|
||||
model="CARD"
|
||||
:request="query"
|
||||
:rowSelection="{
|
||||
selectedRowKeys: _selectedRowKeys,
|
||||
}"
|
||||
@cancelSelect="cancelSelect"
|
||||
:gridColumns="[1, 1, 1]"
|
||||
:defaultParams="{
|
||||
sorts: [
|
||||
{
|
||||
name: 'createTime',
|
||||
order: 'desc',
|
||||
},
|
||||
],
|
||||
terms,
|
||||
}"
|
||||
:params="params"
|
||||
>
|
||||
<template #card="slotProps">
|
||||
<SceneCard
|
||||
:value="slotProps"
|
||||
:status="slotProps.state?.value"
|
||||
:statusText="slotProps.state?.text"
|
||||
:active="_selectedRowKeys.includes(slotProps.id)"
|
||||
@click="handleClick"
|
||||
:statusNames="{
|
||||
started: 'success',
|
||||
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 #title>
|
||||
<Ellipsis style="width: calc(100% - 100px)">
|
||||
<span style="font-size: 16px; font-weight: 600">
|
||||
{{ slotProps.name }}
|
||||
</span>
|
||||
</Ellipsis>
|
||||
</template>
|
||||
<template #subTitle>
|
||||
<Ellipsis :lineClamp="2">
|
||||
说明:{{
|
||||
slotProps?.description ||
|
||||
typeMap.get(slotProps.triggerType)?.tip
|
||||
}}
|
||||
</Ellipsis>
|
||||
</template>
|
||||
</SceneCard>
|
||||
</template>
|
||||
</JTable>
|
||||
</div>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { query } from '@/api/rule-engine/scene';
|
||||
import { bindScene } from '@/api/rule-engine/configuration';
|
||||
import SceneCard from '@/views/rule-engine/Scene/SceneCard.vue';
|
||||
import { getImage } from '@/utils/comm';
|
||||
import { message } from 'ant-design-vue';
|
||||
const columns = [
|
||||
{
|
||||
title: '名称',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
search: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '触发方式',
|
||||
dataIndex: 'triggerType',
|
||||
key: 'triggerType',
|
||||
search: {
|
||||
type: 'select',
|
||||
options: [
|
||||
{
|
||||
label: '手动触发',
|
||||
value: 'manual',
|
||||
},
|
||||
{
|
||||
label: '定时触发',
|
||||
value: 'timer',
|
||||
},
|
||||
{
|
||||
label: '设备触发',
|
||||
value: 'device',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'state',
|
||||
key: 'state',
|
||||
search: {
|
||||
type: 'select',
|
||||
options: [
|
||||
{
|
||||
label: '正常',
|
||||
value: 'started',
|
||||
},
|
||||
{
|
||||
label: '禁用',
|
||||
value: 'disable',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
];
|
||||
const props = defineProps({
|
||||
id: {
|
||||
type: String,
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
},
|
||||
});
|
||||
const terms = [
|
||||
{
|
||||
terms: [
|
||||
{
|
||||
column: 'id',
|
||||
termType: 'alarm-bind-rule$not',
|
||||
value: props.id,
|
||||
type: 'and',
|
||||
},
|
||||
{
|
||||
column: 'triggerType',
|
||||
termType: 'eq',
|
||||
value: props.type === 'other' ? undefined : 'device',
|
||||
},
|
||||
],
|
||||
type: 'and',
|
||||
},
|
||||
];
|
||||
const params = ref();
|
||||
const typeMap = new Map();
|
||||
typeMap.set('manual', {
|
||||
text: '手动触发',
|
||||
img: getImage('/scene/scene-hand.png'),
|
||||
icon: getImage('/scene/trigger-type-icon/manual.png'),
|
||||
tip: '适用于第三方平台向物联网平台下发指令控制设备',
|
||||
});
|
||||
typeMap.set('timer', {
|
||||
text: '定时触发',
|
||||
img: getImage('/scene/scene-timer.png'),
|
||||
icon: getImage('/scene/trigger-type-icon/timing.png'),
|
||||
tip: '适用于定期执行固定任务',
|
||||
});
|
||||
typeMap.set('device', {
|
||||
text: '设备触发',
|
||||
img: getImage('/scene/scene-device.png'),
|
||||
icon: getImage('/scene/trigger-type-icon/device.png'),
|
||||
tip: '适用于设备数据或行为满足触发条件时,执行指定的动作',
|
||||
});
|
||||
const _selectedRowKeys = ref<string[]>([]);
|
||||
const handleClick = (dt: any) => {
|
||||
if (_selectedRowKeys.value.includes(dt.id)) {
|
||||
const _index = _selectedRowKeys.value.findIndex((i) => i === dt.id);
|
||||
_selectedRowKeys.value.splice(_index, 1);
|
||||
} else {
|
||||
_selectedRowKeys.value = [..._selectedRowKeys.value, dt.id];
|
||||
}
|
||||
console.log(_selectedRowKeys.value);
|
||||
};
|
||||
/**
|
||||
* 取消选择事件
|
||||
*/
|
||||
const cancelSelect = () => {
|
||||
_selectedRowKeys.value = [];
|
||||
};
|
||||
const log = () => {};
|
||||
log();
|
||||
const handleSearch = (e: any) => {
|
||||
params.value = e;
|
||||
};
|
||||
const emit = defineEmits(['closeSave','saveScene']);
|
||||
/**
|
||||
* 保存选中关联场景
|
||||
*/
|
||||
const saveCorrelation = async () => {
|
||||
if (_selectedRowKeys.value.length > 0) {
|
||||
const list = _selectedRowKeys.value.map((item: any) => {
|
||||
return {
|
||||
alarmId: props.id,
|
||||
releId: item,
|
||||
};
|
||||
});
|
||||
const res = await bindScene([...list]);
|
||||
if (res.status === 200) {
|
||||
message.success('操作成功');
|
||||
emit('saveScene');
|
||||
}
|
||||
} else {
|
||||
message.error('请选择至少一条数据');
|
||||
}
|
||||
};
|
||||
const closeModal = () => {
|
||||
emit('closeSave');
|
||||
};
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
</style>
|
|
@ -1,9 +1,174 @@
|
|||
<template>
|
||||
<div>123</div>
|
||||
<JTable
|
||||
model="CARD"
|
||||
:request="query"
|
||||
:defaultParams="{
|
||||
sorts: [{ name: 'createTime', order: 'desc' }],
|
||||
terms,
|
||||
}"
|
||||
:gridColumns="[1, 1, 1]"
|
||||
ref="actionRef"
|
||||
>
|
||||
<template #headerTitle>
|
||||
<a-space>
|
||||
<PermissionButton type="primary" @click="showModal">
|
||||
<template #icon><AIcon type="PlusOutlined" /></template>
|
||||
新增
|
||||
</PermissionButton>
|
||||
</a-space>
|
||||
</template>
|
||||
<template #card="slotProps">
|
||||
<SceneCard
|
||||
:value="slotProps"
|
||||
@click="handleClick"
|
||||
:actions="getActions(slotProps, 'card')"
|
||||
:status="slotProps.state?.value"
|
||||
:statusText="slotProps.state?.text"
|
||||
:statusNames="{
|
||||
started: 'success',
|
||||
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 #title>
|
||||
<Ellipsis style="width: calc(100% - 100px)">
|
||||
<span style="font-size: 16px; font-weight: 600">
|
||||
{{ slotProps.name }}
|
||||
</span>
|
||||
</Ellipsis>
|
||||
</template>
|
||||
<template #subTitle>
|
||||
<Ellipsis :lineClamp="2">
|
||||
说明:{{
|
||||
slotProps?.description ||
|
||||
typeMap.get(slotProps.triggerType)?.tip
|
||||
}}
|
||||
</Ellipsis>
|
||||
</template>
|
||||
<template #actions="item">
|
||||
<PermissionButton
|
||||
:disabled="item.disabled"
|
||||
:popConfirm="item.popConfirm"
|
||||
:tooltip="{
|
||||
...item.tooltip,
|
||||
}"
|
||||
@click="item.onClick"
|
||||
>
|
||||
<AIcon :type="item.icon" />
|
||||
<span>{{ item?.text }}</span>
|
||||
</PermissionButton>
|
||||
</template>
|
||||
</SceneCard>
|
||||
</template>
|
||||
</JTable>
|
||||
<Save
|
||||
:id="id"
|
||||
:type="configurationData.current?.targetType"
|
||||
@close-save="closeSave"
|
||||
@save-scene="saveSuccess"
|
||||
v-if="visible"
|
||||
></Save>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { query } from '@/api/rule-engine/scene';
|
||||
import { unbindScene } from '@/api/rule-engine/configuration';
|
||||
import { useRoute } from 'vue-router';
|
||||
import SceneCard from '@/views/rule-engine/Scene/SceneCard.vue';
|
||||
import type { ActionsType } from '@/components/Table';
|
||||
import { getImage } from '@/utils/comm';
|
||||
import { message } from 'ant-design-vue/es';
|
||||
import Save from './save/index.vue';
|
||||
import { useAlarmConfigurationStore } from '@/store/alarm';
|
||||
import { storeToRefs } from 'pinia';
|
||||
const route = useRoute();
|
||||
const id = route.query?.id;
|
||||
|
||||
const alarmConfigurationStore = useAlarmConfigurationStore();
|
||||
const { configurationData } = storeToRefs(alarmConfigurationStore);
|
||||
|
||||
const terms = [
|
||||
{
|
||||
terms: [
|
||||
{
|
||||
column: 'id',
|
||||
termType: 'alarm-bind-rule',
|
||||
value: id,
|
||||
},
|
||||
],
|
||||
type: 'and',
|
||||
},
|
||||
];
|
||||
const actionRef = ref();
|
||||
const typeMap = new Map();
|
||||
typeMap.set('manual', {
|
||||
text: '手动触发',
|
||||
img: getImage('/scene/scene-hand.png'),
|
||||
icon: getImage('/scene/trigger-type-icon/manual.png'),
|
||||
tip: '适用于第三方平台向物联网平台下发指令控制设备',
|
||||
});
|
||||
typeMap.set('timer', {
|
||||
text: '定时触发',
|
||||
img: getImage('/scene/scene-timer.png'),
|
||||
icon: getImage('/scene/trigger-type-icon/timing.png'),
|
||||
tip: '适用于定期执行固定任务',
|
||||
});
|
||||
typeMap.set('device', {
|
||||
text: '设备触发',
|
||||
img: getImage('/scene/scene-device.png'),
|
||||
icon: getImage('/scene/trigger-type-icon/device.png'),
|
||||
tip: '适用于设备数据或行为满足触发条件时,执行指定的动作',
|
||||
});
|
||||
const getActions = (
|
||||
data: Partial<Record<string, any>>,
|
||||
type: 'card' | 'table',
|
||||
): ActionsType[] => {
|
||||
if (!data) return [];
|
||||
const actions: ActionsType[] = [
|
||||
{
|
||||
key: 'unbind',
|
||||
text: '解绑',
|
||||
icon: 'DisconnectOutlined',
|
||||
popConfirm: {
|
||||
title: '确定解绑?',
|
||||
onConfirm: async () => {
|
||||
const res = await unbindScene(id, [data.id]);
|
||||
if (res.status === 200) {
|
||||
message.success('操作成功');
|
||||
actionRef.value.reload();
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
return actions;
|
||||
};
|
||||
const visible = ref(false);
|
||||
const log = () => {
|
||||
console.log();
|
||||
};
|
||||
log();
|
||||
const showModal = () => {
|
||||
visible.value = true;
|
||||
};
|
||||
const closeSave = () => {
|
||||
visible.value = false;
|
||||
};
|
||||
const saveSuccess = () =>{
|
||||
visible.value = false;
|
||||
actionRef.value.reload();
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
</style>
|
|
@ -8,7 +8,9 @@
|
|||
<a-tab-pane key="2" tab="关联场景联动">
|
||||
<Scene></Scene>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="3" tab="告警记录"></a-tab-pane>
|
||||
<a-tab-pane key="3" tab="告警记录">
|
||||
<Log/>
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</a-card>
|
||||
</page-container>
|
||||
|
@ -17,7 +19,8 @@
|
|||
<script lang="ts" setup>
|
||||
import Base from './Base/index.vue';
|
||||
import Scene from './Scene/index.vue'
|
||||
const activeKey = ref('2');
|
||||
import Log from './Log/indev.vue'
|
||||
const activeKey = ref('1');
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
</style>
|
|
@ -280,11 +280,6 @@ let params = ref({
|
|||
sorts: [{ name: 'alarmTime', order: 'desc' }],
|
||||
terms: [],
|
||||
});
|
||||
let param = reactive({
|
||||
pageSize: 10,
|
||||
terms: [],
|
||||
});
|
||||
|
||||
const handleSearch = async (params: any) => {
|
||||
const resp = await query(params);
|
||||
if (resp.status === 200) {
|
||||
|
|
Loading…
Reference in New Issue